This commit is contained in:
2024-07-01 23:05:02 +02:00
parent 18524d8955
commit da9d3a1f39
117 changed files with 0 additions and 41694 deletions

View File

@@ -1,28 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Upload your config**
Press the "raw" button in the SmartEVSE webserver and upload the json settings file, so we can look at your configuration.
**Upload a debug log**
Flash the debug version of the firmware (see https://github.com/dingo35/SmartEVSE-3.5/blob/master/SmartEVSE-3/HowToFlash.txt), telnet to your device, capture the debug log, cut it so that it shows JUST BEFORE and JUST AFTER the problem arises, and upload it here.
**To Reproduce**
Steps to reproduce the behavior:
1. What Mode are you in? Normal, Smart or Solar?
2. What steps do you take so the problem arises?
**Expected behavior**
A clear and concise description of what you expected to happen; expected Charging Current?
**Screenshots**
Only add screenshots if it adds any information, e.g. when you are reporting a problem on the webserver screen.

View File

@@ -1,21 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
ALSO, if your feature request relates to any reported issues previously, please LINK them here!
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,130 +0,0 @@
name: PlatformIO CI
on:
workflow_call:
inputs:
major:
required: true
type: string
minor:
required: true
type: string
patch:
required: true
type: string
prerelease:
required: false
type: string
outputs:
artifact:
description: "The first output string"
value: ${{ jobs.build.outputs.artifact }}
push:
branches:
- master
- release/*
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Get current branch
id: branch
run: echo "branch=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
- name: Get current datetime
id: datetime
run: echo "datetime=$(date +'%Y%m%dT%H%M%S')" >> $GITHUB_OUTPUT
- name: Get current time
id: time
run: echo "time=$(date +'%H%M%S')" >> $GITHUB_OUTPUT
- name: Get version
id: version
shell: bash
run: |
if [ -z "${{ inputs.major }}" ]
then
echo "version=${{ steps.time.outputs.time }}" >> $GITHUB_OUTPUT
else
if [ -z "${{ inputs.prerelease }}" ]
then
echo "version=${{ inputs.major }}.${{ inputs.minor }}.${{ inputs.patch }}" >> $GITHUB_OUTPUT
else
echo "version=${{ inputs.major }}.${{ inputs.minor }}.${{ inputs.patch }}-${{ inputs.prerelease }}" >> $GITHUB_OUTPUT
fi
fi
- uses: actions/checkout@v3
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: '${{ runner.os }}-pip-${{ hashFiles(''**/requirements.txt'') }}'
restore-keys: |
${{ runner.os }}-pip-
- name: Cache PlatformIO
uses: actions/cache@v3
with:
path: ~/.platformio
key: '${{ runner.os }}-${{ hashFiles(''**/lockfiles'') }}'
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Install libs
run: |
cd SmartEVSE-3
pio lib install
- name: Build normal version
env:
super_secret: ${{ secrets.SECRET_RSA_KEY }}
run: |
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=0' pio run -d SmartEVSE-3/
# Create a temporary file
secret_file=$(mktemp)
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
echo "$super_secret" > "$secret_file"
# Create signature file
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
# throw it all in one file
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
# Remove the temporary file
rm -f "$secret_file"
- name: Upload firmware.bin
uses: actions/upload-artifact@v3
with:
name: dists_zip
path: ./SmartEVSE-3/.pio/build/release/*.bin
retention-days: 10
- name: Upload HowToFlash.txt
uses: actions/upload-artifact@v3
with:
name: dists_zip
path: ./SmartEVSE-3/HowToFlash.txt
retention-days: 10
- name: Build debug version
env:
super_secret: ${{ secrets.SECRET_RSA_KEY }}
run: |
PLATFORMIO_BUILD_FLAGS='-DVERSION=\"v${{ steps.version.outputs.version }}\" -DDBG=1' pio run -d SmartEVSE-3/
# Create a temporary file
secret_file=$(mktemp)
# Write the secret to the temporary file, because passing it as command line argument might reveal it for users using ps -a
echo "$super_secret" > "$secret_file"
# Create signature file
openssl dgst -sign "$secret_file" -keyform PEM -sha256 -out firmware.sign -binary ./SmartEVSE-3/.pio/build/release/firmware.bin
# throw it all in one file
cat firmware.sign ./SmartEVSE-3/.pio/build/release/firmware.bin > ./SmartEVSE-3/.pio/build/release/firmware.signed.bin
# Remove the temporary file
rm -f "$secret_file"
mv ./SmartEVSE-3/.pio/build/release/firmware.bin ./SmartEVSE-3/.pio/build/release/firmware.debug.bin
mv ./SmartEVSE-3/.pio/build/release/firmware.signed.bin ./SmartEVSE-3/.pio/build/release/firmware.debug.signed.bin
- name: Upload Artifact debug firmware
uses: actions/upload-artifact@v3
with:
name: dists_zip
path: ./SmartEVSE-3/.pio/build/release/*.bin
retention-days: 10
outputs:
artifact: dists_zip

View File

@@ -1,62 +0,0 @@
on:
push:
tags:
- 'v*'
name: Create Release
jobs:
version:
runs-on: ubuntu-latest
steps:
- id: get_version
uses: battila7/get-version-action@v2
outputs:
major: ${{ steps.get_version.outputs.major }}
minor: ${{ steps.get_version.outputs.minor }}
patch: ${{ steps.get_version.outputs.patch }}
prerelease: ${{ steps.get_version.outputs.prerelease }}
build:
needs: version
uses: ./.github/workflows/pio-build.yaml
with:
major: ${{ needs.version.outputs.major }}
minor: ${{ needs.version.outputs.minor }}
patch: ${{ needs.version.outputs.patch }}
prerelease: ${{ needs.version.outputs.prerelease }}
secrets: inherit
release:
permissions: write-all
needs: build
name: Upload Release Asset
runs-on: ubuntu-latest
steps:
- name: Get current tag
id: tag
run: echo "tag=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
id: download
with:
path: dist
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: true
- name: Zip
run: zip -j ${{ steps.tag.outputs.tag }}-dist.zip ./dist/${{ needs.build.outputs.artifact }}/*
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./${{ steps.tag.outputs.tag }}-dist.zip
asset_name: ${{ steps.tag.outputs.tag }}-dist.zip
asset_content_type: application/zip

View File

@@ -1,11 +0,0 @@
.pio
.log
sdkconfig.*
*/.vscode/.browse.c_cpp.db*
*/.vscode/c_cpp_properties.json
*/.vscode/launch.json
*/.vscode/ipch
.DS_Store
*/.DS_Store
.idea

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2021 SmartEVSE
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.

View File

@@ -1,65 +0,0 @@
SmartEVSE v3
=========
Smart Electric Vehicle Charge Controller
![Image of SmartEVSE](/pictures/SmartEVSEv3.png)
# What is it?
It's an open source EVSE (Electric Vehicle Supply Equipment). It supports 1-3 phase charging, fixed charging cable or charging socket. Locking actuator support (5 different types). And it can directly drive a mains contactor for supplying power to the EV. It features a display from which all module parameters can be configured.<br>
Up to 8 modules can be connected together to charge up to eight EV's from one mains connection without overloading it.<br>
The mains connection can be monitored by the (optional) sensorbox or a modbus kWh meter. This allows smart charging.
Communication between the SmartEVSE(s) / Sensorbox or kWh meters is done over RS485(modbus).
# Features
- Fits into a standard DIN rail enclosure.
- Measures the current consumption of other appliances, and automatically lowers or increases the charging current to the EV. (sensorbox required)
- The load balancing feature let's you connect up to 8 SmartEVSE's to one mains supply.
- Two switched 230VAC outputs, for contactors.
- Powered RS485 communication bus for sensorbox / Modbus kWh Meters.
- Can be used with fixed cable, or socket and charging cable.
- Automatically selects current capacity of the connected cable (13/16/32A)
- Locking actuator support, locks the charging cable in the socket.
- RFID reader support, restrict the use of the charging station to max 20 RFID cards.
- An optional modbus kWh meter will measure power and charged energy, and display this on the LCD.
- Built-in temperature sensor.
- RGB led output for status information while charging.
- All module parameters can be configured using the display and buttons.
- WiFi status page.
- Firmware upgradable through USB-C port or through the built in webserver.
- REST API for communication with external software (e.g. HomeAssistant)
- MQTT API
- Rudimentary support for home batteries
- Supporting delayed charging
# Connecting the SmartESVE to WiFi
In order to connect the SmartEVSE to your local WiFi network, a temporarily hotspot is created by the SmartESVE to which you can connect using a phone/tablet.
Here you can then scan for your local WiFi, and enter your Wifi network password. Then the SmartEVSE will use this information to connect to your local Wifi network.
The steps to connect the SmartEVSE to Wifi are as follows:
- in the SmartEVSE menu, go to the option WIFI, then select SetupWiFi.
- after 10 seconds, a hotspot/access point SmartESVE-xxxx is started. (xxxx is the serial nr of your SmartEVSE)
- Using a phone or tablet, connect to this access point.
- You will be asked to enter a password. This password is visible on the top right corner of the SmartEVSE's display. (PW:xxxxxxxx)
- Once connected you will be able to select your local WiFi network, and enter the password for this network.
- click SAVE, the SmartEVSE will try to connect to your local WiFi network.
- Enter the menu of your SmartEVSE again. The SmartEVSE should now display the IP address on the top row of the display.
- use this IP address in a webbrowser to connect to the webserver of the controller. You can also use http://smartevse-xxxx.local (replace xxxx with the serial nr of your controller)
# Updating Firmware
Connect the SmartEVSE controller to your WiFi network (using the menu of the SmartEVSE), and then browse to http://IPaddress/update where IPaddress is the IP which is shown on the display.
You can also use http://smartevse-xxxx.local/update where xxxx is the serial nr of your controller.<br>
Here you can select the firmware.bin and press update to update the firmware.<br>
It's also possible to update the spiffs partition from this page. (for v3.0.1 this is not needed)<br>
After updating the firmware, you can access the status page again using the normal url: http://smartevse-xxxx.local (replace xxxx with the serial nr of your controller)<br>
# Documentation
[Hardware installation](docs/installation.md)<br>
[Configuration](docs/configuration.md)<br>
[Operation](docs/operation.md)<br>

View File

@@ -1,5 +0,0 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -1,3 +0,0 @@
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(SmartEVSE32)

View File

@@ -1,5 +0,0 @@
-surf to http://your-smartevse/update
-select the firmware.bin from this archive, OR if you want the debug version (via telnet over your wifi),
rename firmware.debug.bin to firmware.bin and select that. YOU CANNOT FLASH A FILE WITH ANOTHER NAME!
-if you get FAIL, check your wifi connection and try again;
-after OK, wait 10-30 seconds and your new firmware including the webserver should be online!

View File

@@ -1,13 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIB4DCCAYWgAwIBAgIUZNoNpf/c2H+t54PnIoe4PgiahV0wCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA1MDQwNjEyMDNaFw0yNDA2MDMw
NjEyMDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAAQLQqPNIgyYn4J8SE3LRBVhkDyLAT6cumGL73QGB+OzEsj6cv2B0kGs
jpvUrsclwmCVLVo0T6FxHR4Pw/Fy3qgvo1MwUTAdBgNVHQ4EFgQUpqjPZrPqhA23
ghR5bdmj0gceVRgwHwYDVR0jBBgwFoAUpqjPZrPqhA23ghR5bdmj0gceVRgwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA2IitVasCjmRsbz9ZcG4U
jn3tudAVCXs9Fet7AVLNvDkCIQDJGRWuWmctvD/7DBPUra822bIlWhwFKljWpNTW
wZAdFg==
-----END CERTIFICATE-----

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICtA0BJEavg6pVMl6lcPOA5I7qqm4W/CoFbJSP/osM3poAoGCCqGSM49
AwEHoUQDQgAEC0KjzSIMmJ+CfEhNy0QVYZA8iwE+nLphi+90BgfjsxLI+nL9gdJB
rI6b1K7HJcJglS1aNE+hcR0eD8Pxct6oLw==
-----END EC PRIVATE KEY-----

View File

@@ -1,14 +0,0 @@
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtjEWhkfKPAUrtX1GueYq
JmDp4qSHBG6ndwikAHvteKgWQABDpwaemZdxh7xVCuEdjEkaecinNOZ0LpSCF3QO
qflnXkvpYVxjdTpKBxo7vP5QEa3I6keJfwpoMzGuT8XOK7id6FHJhtYEXcaufALi
mR/NXT11ikHLtluATymPdoSscMiwry0qX03yIek91lDypBNl5uvD2jxn9smlijfq
9j0lwtpLBWJPU8vsU0uzuj7Qq5pWZFKsjiNWfbvNJXuLsupOazf5sh0yeQzL1CBL
RUsBlYVoChTmSOyvi6kO5vW/6GLOafJF0FTdOQ+Gf3/IB6M1ErSxlqxQhHq0pb7Y
INl7+aFCmlRjyLlMjb8xdtuedlZKv8mLd37AyPAihrq9gV74xq6c7w2y+h9213p8
jgcmo/HvOlGaXEIOVCUu102teOckXjTni2yhEtFISCaWuaIdb5P9e0uBIy1e+Bi6
/7A3aut5MQP07DO99BFETXyFF6EixhTF8fpwVZ5vXeIDvKKEDUGuzAziUEGIZpic
UQ2fmTzIaTBbNlCMeTQFIpZCosM947aGKNBp672wdf996SRwg9E2VWzW2Z1UuwWV
BPVQkHb1Hsy7C9fg5JcLKB9zEfyUH0Tm9Iur1vsuA5++JNl2+T55192wqyF0R9sb
YtSTUJNSiSwqWt1m0FLOJD0CAwEAAQ==
-----END PUBLIC KEY-----

File diff suppressed because one or more lines are too long

View File

@@ -1,173 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SmartEVSEv3</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
#container { margin-right: auto; margin-left: auto; max-width: 900px; }
#info { background: #e0f0f0; border-radius: .5em; padding: 2em; }
#wrapper { margin-top: 1em; }
</style>
<script>
let OWNER_FACT="SmartEVSE";
let REPO_FACT="SmartEVSE-3";
let OWNER_COMM="dingo35";
let REPO_COMM="SmartEVSE-3.5";
function update_comm() {
window.location.href = "/autoupdate?url=community&debug=0";
}
function update_fact() {
window.location.href = "/autoupdate?url=factory&debug=0";
}
function update_comm_debug() {
window.location.href = "/autoupdate?url=community&debug=1";
}
function update_fact_debug() {
window.location.href = "/autoupdate?url=factory&debug=1";
}
</script>
</head>
<body onload="loadData()">
<div id="container">
<div id="info">
Current version: <span id="version"></span>
=======================================================
DOWNLOADING
<br><br>
<table style='text-align: left'>
<tr>
<th>Distribution:</th>
<th>Status:</th>
<th>Github repo:</th>
<th>Latest version:</th>
<th>Flash:</th>
</tr>
<tr>
<td>Factory</td>
<td>stable</td>
<td><a href="https://github.com/"
onclick="location.href=this.href + OWNER_FACT + '/' + REPO_FACT + '/releases';return false;"><script>document.write(OWNER_FACT)</script></a></td>
<td><div id="latest_fact"></div></td>
<td><button onclick="update_fact()" style="width: 100px; display:inline-block;">Standard</button>
<td><button onclick="update_fact_debug()" style="width: 100px; display:inline-block;">Debug</button>
</tr>
<tr>
<td>Community&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</td>
<td>bleeding edge&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</td>
<td><a href="https://github.com/"
onclick="location.href=this.href + OWNER_COMM + '/' + REPO_COMM + '/releases';return false;"><script>document.write(OWNER_COMM)</script></a></td>
<td><div id="latest_comm"></div></td>
<td><button onclick="update_comm()" style="width: 100px; display:inline-block;">Standard</button>
<td><button onclick="update_comm_debug()" style="width: 100px; display:inline-block;">Debug</button>
</tr>
</table>
<br>
=======================================================
<br>
FLASHING
<br><br>
Flash one of:<ul>
<li>firmware.bin or firmware.signed.bin (to update the firmware);</li>
<li>firmware.debug.bin or firmware.debug.signed.bin (if you want to telnet to your SmartEVSE to see debug messages);</li>
<li>rfix.txt (if you want to bulk upload allowed NFC tags for the RFID reader);</li>
</ul>
You should only flash files with those exact names.<br>No need to flash spiffs.bin for versions 3.6.0-RC1 and newer!<br>No need to rename firmware.debug.bin anymore for versions 3.6.0-RC2 and newer!<br>Signed firmware is verified to be original and can be handled by versions 3.6.2 and newer.
</div>
<div id="wrapper">
<input type="file" id="el1" style="display: none"/>
<button id="el2">choose file...</button>
<div id="el3"></div>
</div>
</div>
</body>
<script type="module">
// Octokit.js
// https://github.com/octokit/core.js#readme
import { Octokit } from "https://esm.sh/@octokit/core";
window.loadData=loadData;
function loadData() {
document.getElementById("version").innerHTML = sessionStorage.getItem("version");
getLatestVersion(OWNER_FACT, REPO_FACT, 'latest_fact');
getLatestVersion(OWNER_COMM, REPO_COMM, 'latest_comm');
}
async function getLatestVersion(owner, repo, element) {
const octokit = new Octokit({
})
try {
const result = await octokit.request('GET /repos/{owner}/{repo}/releases/latest', {
owner: owner,
repo: repo,
headers: {
'X-GitHub-Api-Version': '2022-11-28'
}
})
//asset_id=result.data.assets.filter(function(entry){ return entry.name==="firmware.signed.bin";})[0].id;
//console.log(asset_id);
//console.log(JSON.stringify(result.data.assets));
document.getElementById(element).innerHTML = result.data.tag_name;
} catch (error) {
console.error(error.message);
}
}
// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
// Helper function to display upload status
var setStatus = function(text) {
document.getElementById('el3').innerText = text;
};
// When user clicks on a button, trigger file selection dialog
var button = document.getElementById('el2');
button.onclick = function(ev) {
input.click();
};
// Send a large blob of data chunk by chunk
var sendFileData = function(name, data, chunkSize) {
var sendChunk = function(offset) {
var chunk = data.subarray(offset, offset + chunkSize) || '';
var opts = {method: 'POST', body: chunk};
var url = '/update?offset=' + offset + '&file=' + encodeURIComponent(name) + '&size=' + data.length;
var ok;
if (offset + chunk.length == data.length) {
setStatus('Upload of ' + name + ' finished, you can close this page.');
window.location.href = "/";
}
else
setStatus('Uploading ' + name + ', bytes ' + offset + '..' + (offset + chunk.length) + ' of ' + data.length);
fetch(url, opts)
.then(function(res) {
if (res.ok && chunk.length > 0) sendChunk(offset + chunk.length);
ok = res.ok;
return res.text();
})
.then(function(text) {
if (!ok) setStatus('Error: ' + text);
});
};
sendChunk(0);
};
// If user selected a file, read it into memory and trigger sendFileData()
var input = document.getElementById('el1');
input.onchange = function(ev) {
if (!ev.target.files[0]) return;
var f = ev.target.files[0], r = new FileReader();
r.readAsArrayBuffer(f);
r.onload = function() {
ev.target.value = '';
sendFileData(f.name, new Uint8Array(r.result), 20480);
};
};
</script>
</html>

View File

@@ -1,43 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SmartEVSEv3</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script>
function fetchProgress() {
fetch('/autoupdate_progress')
.then(res => res.json())
.then(data => {
// code to handle the response
var mainContainer = document.getElementById("myData");
var div = document.createElement("div");
mainContainer.innerHTML = '';
if (data.progress == -1) { //sucess
div.innerHTML = 'Firmware update succesfully completed, will reboot.';
}
else {
if (data.progress == -2) { //fail
div.innerHTML = 'ERROR: Firmware update fail; rebooting.';
} else {
div.innerHTML = 'Firmware update progress: ' + data.progress + '/' + data.size;
}
}
mainContainer.appendChild(div);
})
.catch(err => {
console.error('Error: ', err)
})
}
window.addEventListener('load', function () {
// Your document is loaded.
var fetchInterval = 1000; // 1 seconds.
// Invoke the request every 1 seconds.
setInterval(fetchProgress, fetchInterval);
});
</script>
</head>
<body>
<div id="myData"></div>
</body>
</html>

View File

@@ -1,36 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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.
*/
#ifndef __ONEWIRE_H
#define __ONEWIRE_H
extern Preferences preferences;
void ReadRFIDlist(void);
void DeleteAllRFID(void);
void CheckRFID(void);
void LoadandStoreRFID(unsigned int *RFIDparam);
#endif // #ifndef __ONEWIRE_H

View File

@@ -1,39 +0,0 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@@ -1,592 +0,0 @@
/*
; Project: Smart EVSE v3
;
;
; 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.
*/
#ifndef __EVSE_MAIN
#define __EVSE_MAIN
#ifndef DBG
//the wifi-debugger is available by telnetting to your SmartEVSE device
#define DBG 0 //comment or set to 0 for production release, 0 = no debug 1 = debug over telnet, 2 = debug over usb serial
#endif
#ifndef FAKE_RFID
//set FAKE_RFID to 1 to emulate an rfid reader with rfid of card = 123456
//showing the rfid card is simulated by executing http://smartevse-xxx.lan/debug?showrfid=1
//don't forget to first store the card before it can activate charging
#define FAKE_RFID 0
#endif
#ifndef AUTOMATED_TESTING
//set AUTOMATED_TESTING to 1 to make hardware-related paramaters like MaxCurrent and MaxCircuit updatable via REST API
//e.g. by executing curl -X POST http://smartevse-xxx.lan/automated_testing?maxcurrent=100
#define AUTOMATED_TESTING 0
#endif
#ifndef FAKE_SUNNY_DAY
//set this to 1 to emulate a sunny day where your solar charger is injecting current in the grid:
#define FAKE_SUNNY_DAY 0
//disclaimer: might not work for CT1 calibration/uncalibration stuff, since I can't test that
//the number of Amperes you want to have fake injected into Lx
#endif
#if FAKE_SUNNY_DAY
#define INJECT_CURRENT_L1 10
#define INJECT_CURRENT_L2 0
#define INJECT_CURRENT_L3 0
#endif
#ifndef MQTT
#define MQTT 1 // Uncomment or set to 0 to disable MQTT support in code
#endif
#ifndef MODEM
//the wifi-debugger is available by telnetting to your SmartEVSE device
#define MODEM 0 //0 = no modem 1 = modem
#endif
#ifndef VERSION
//please note that this version will only be displayed with the correct time/date if the program is recompiled
//so the webserver will show correct version if evse.cpp is recompiled
//the lcd display will show correct version if glcd.cpp is recompiled
#define VERSION (__TIME__ " @" __DATE__)
#endif
#if DBG == 0
//used to steer RemoteDebug
#define DEBUG_DISABLED 1
#define _LOG_W( ... ) //dummy
#define _LOG_I( ... ) //dummy
#define _LOG_D( ... ) //dummy
#define _LOG_V( ... ) //dummy
#define _LOG_A( ... ) //dummy
#define _LOG_W_NO_FUNC( ... ) //dummy
#define _LOG_I_NO_FUNC( ... ) //dummy
#define _LOG_D_NO_FUNC( ... ) //dummy
#define _LOG_V_NO_FUNC( ... ) //dummy
#define _LOG_A_NO_FUNC( ... ) //dummy
#endif
#if DBG == 1
#define _LOG_A(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Always = Errors!!!
#define _LOG_P(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define _LOG_V(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Verbose
#define _LOG_D(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Debug
#define _LOG_I(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Info
#define _LOG_W(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Warning
#define _LOG_E(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__) //Error not used!
#define _LOG_A_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_P_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_V_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_D_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_I_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_W_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf(fmt, ##__VA_ARGS__)
#define _LOG_E_NO_FUNC(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf(fmt, ##__VA_ARGS__)
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
extern RemoteDebug Debug;
#endif
#if DBG == 2
#define DEBUG_DISABLED 1
#define _LOG_W( ... ) log_w ( __VA_ARGS__ )
#define _LOG_I( ... ) log_i ( __VA_ARGS__ )
#define _LOG_D( ... ) log_d ( __VA_ARGS__ )
#define _LOG_V( ... ) log_v ( __VA_ARGS__ )
#define _LOG_A( ... ) log_n ( __VA_ARGS__ )
#define _LOG_W_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
#define _LOG_I_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
#define _LOG_D_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
#define _LOG_V_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
#define _LOG_A_NO_FUNC( ... ) Serial.printf ( __VA_ARGS__ )
#endif
// Pin definitions left side ESP32
#define PIN_TEMP 36
#define PIN_CP_IN 39
#define PIN_PP_IN 34
#define PIN_LOCK_IN 35
#define PIN_SSR 32
#define PIN_LCD_SDO_B3 33 // = SPI_MOSI
#define PIN_LCD_A0_B2 25
#define PIN_LCD_CLK 26 // = SPI_SCK
#define PIN_SSR2 27
#define PIN_LCD_LED 14
#define PIN_LEDB 12
#define PIN_RCM_FAULT 13
// Pin definitions right side ESP32
#define PIN_RS485_RX 23
#define PIN_RS485_DIR 22
//#define PIN_RXD
//#define PIN_TXD
#define PIN_RS485_TX 21
#define PIN_CP_OUT 19
#define PIN_ACTB 18
#define PIN_LCD_RST 5
#define PIN_ACTA 17
#define PIN_SW_IN 16
#define PIN_LEDG 4
#define PIN_IO0_B1 0
#define PIN_LEDR 2
#define PIN_CPOFF 15
#define SPI_MOSI 33 // SPI connections to LCD
#define SPI_MISO -1
#define SPI_SCK 26
#define SPI_SS -1
#define CP_CHANNEL 0
#define RED_CHANNEL 2 // PWM channel 2 (0 and 1 are used by CP signal)
#define GREEN_CHANNEL 3
#define BLUE_CHANNEL 4
#define LCD_CHANNEL 5 // LED Backlight LCD
#define PWM_5 50 // 5% of PWM
#define PWM_95 950 // 95% of PWM
#define PWM_100 1000 // 100% of PWM
#define ICAL 1024 // Irms Calibration value (for Current transformers)
#define MAX_MAINS 25 // max Current the Mains connection can supply
#define MAX_SUMMAINS 600 // only used for capacity rate limiting, max current over the sum of all phases
#define MAX_CURRENT 13 // max charging Current for the EV
#ifndef MIN_CURRENT
#define MIN_CURRENT 6 // minimum Current the EV will accept
#endif
#define MODE 0 // Normal EVSE mode
#define LOCK 0 // No Cable lock
#define MAX_CIRCUIT 16 // Max current of the EVSE circuit breaker
#define CONFIG 0 // Configuration: 0= TYPE 2 socket, 1= Fixed Cable
#define LOADBL 0 // Load Balancing disabled
#define SWITCH 0 // 0= Charge on plugin, 1= (Push)Button on IO2 is used to Start/Stop charging.
#define RC_MON 0 // Residual Current Monitoring on IO3. Disabled=0, RCM14=1
#define CHARGEDELAY 60 // Seconds to wait after overcurrent, before trying again
#define BACKLIGHT 120 // Seconds delay for the LCD backlight to turn off.
#define RFIDLOCKTIME 60 // Seconds delay for the EVSE to lock again (RFIDreader = EnableOne)
#define START_CURRENT 4 // Start charging when surplus current on sum of all phases exceeds 4A (Solar)
#define STOP_TIME 10 // Stop charging after 10 minutes at MIN charge current (Solar)
#define IMPORT_CURRENT 0 // Allow the use of grid power when solar charging (Amps)
#define MAINS_METER 0 // Mains Meter, 0=Disabled, 1= Sensorbox, 2=Phoenix, 3= Finder, 4= Eastron, 5=Custom
#define GRID 0 // Grid, 0= 4-Wire CW, 1= 4-Wire CCW, 2= 3-Wire CW, 3= 3-Wire CCW
#define MAINS_METER_ADDRESS 10
#define PV_METER 0
#define PV_METER_ADDRESS 11
#define EV_METER 0
#define EV_METER_ADDRESS 12
#define MIN_METER_ADDRESS 10
#define MAX_METER_ADDRESS 247
#define EMCUSTOM_ENDIANESS 0
#define EMCUSTOM_DATATYPE 0
#define EMCUSTOM_FUNCTION 4
#define EMCUSTOM_UREGISTER 0
#define EMCUSTOM_UDIVISOR 8
#define EMCUSTOM_IREGISTER 0
#define EMCUSTOM_IDIVISOR 8
#define EMCUSTOM_PREGISTER 0
#define EMCUSTOM_PDIVISOR 8
#define EMCUSTOM_EREGISTER 0
#define EMCUSTOM_EDIVISOR 8
#define RFID_READER 0
#define ACCESS_BIT 1
#define WIFI_MODE 0
#define AP_PASSWORD "00000000"
#define CARD_OFFSET 0
#define INITIALIZED 0
#define ENABLE_C2 ALWAYS_ON
#define MAX_TEMPERATURE 65
#define DELAYEDSTARTTIME 0 // The default StartTime for delayed charged, 0 = not delaying
#define DELAYEDSTOPTIME 0 // The default StopTime for delayed charged, 0 = not stopping
#define SOLARSTARTTIME 40 // Seconds to keep chargecurrent at 6A
#define PUBLIC_KEY "5c7a848c3445793002487608a65fa259cefb16790f7c2f4a1d10af702393f7db\0";
// Mode settings
#define MODE_NORMAL 0
#define MODE_SMART 1
#define MODE_SOLAR 2
#define MODBUS_BAUDRATE 9600
#define MODBUS_TIMEOUT 4
#define ACK_TIMEOUT 1000 // 1000ms timeout
#define NR_EVSES 8
#define BROADCAST_ADR 0x09
#define COMM_TIMEOUT 11 // Timeout for MainsMeter
#define COMM_EVTIMEOUT 8*NR_EVSES // Timeout for EV Energy Meters
#define STATE_A 0 // A Vehicle not connected
#define STATE_B 1 // B Vehicle connected / not ready to accept energy
#define STATE_C 2 // C Vehicle connected / ready to accept energy / ventilation not required
#define STATE_D 3 // D Vehicle connected / ready to accept energy / ventilation required (not implemented)
#define STATE_COMM_B 4 // E State change request A->B (set by node)
#define STATE_COMM_B_OK 5 // F State change A->B OK (set by master)
#define STATE_COMM_C 6 // G State change request B->C (set by node)
#define STATE_COMM_C_OK 7 // H State change B->C OK (set by master)
#define STATE_ACTSTART 8 // I Activation mode in progress
#define STATE_B1 9 // J Vehicle connected / EVSE not ready to deliver energy: no PWM signal
#define STATE_C1 10 // K Vehicle charging / EVSE not ready to deliver energy: no PWM signal (temp state when stopping charge from EVSE)
#define STATE_MODEM_REQUEST 11 // L Vehicle connected / requesting ISO15118 communication, 0% duty
#define STATE_MODEM_WAIT 12 // M Vehicle connected / requesting ISO15118 communication, 5% duty
#define STATE_MODEM_DONE 13 // Modem communication succesful, SoCs extracted. Here, re-plug vehicle
#define STATE_MODEM_DENIED 14 // Modem access denied based on EVCCID, re-plug vehicle and try again
#define NOSTATE 255
#define PILOT_12V 1 // State A - vehicle disconnected
#define PILOT_9V 2 // State B - vehicle connected
#define PILOT_6V 3 // State C - EV charge
#define PILOT_3V 4
#define PILOT_DIODE 5
#define PILOT_NOK 0
#define NO_ERROR 0
#define LESS_6A 1
#define CT_NOCOMM 2
#define TEMP_HIGH 4
#define EV_NOCOMM 8
#define RCM_TRIPPED 16 // RCM tripped. >6mA DC residual current detected.
#define NO_SUN 32
#define Test_IO 64
#define BL_FLASH 128
#define STATE_A_LED_BRIGHTNESS 40
#define STATE_B_LED_BRIGHTNESS 255
#define ERROR_LED_BRIGHTNESS 255
#define WAITING_LED_BRIGHTNESS 255
#define LCD_BRIGHTNESS 255
#define CP_ON digitalWrite(PIN_CPOFF, LOW);
#define CP_OFF digitalWrite(PIN_CPOFF, HIGH);
#define PILOT_CONNECTED digitalWrite(PIN_CPOFF, LOW);
#define PILOT_DISCONNECTED digitalWrite(PIN_CPOFF, HIGH);
#define CONTACTOR1_ON _LOG_A("Switching Contactor1 ON.\n"); digitalWrite(PIN_SSR, HIGH);
#define CONTACTOR1_OFF _LOG_A("Switching Contactor1 OFF.\n"); digitalWrite(PIN_SSR, LOW);
#define CONTACTOR2_ON _LOG_A("Switching Contactor2 ON.\n"); digitalWrite(PIN_SSR2, HIGH);
#define CONTACTOR2_OFF _LOG_A("Switching Contactor2 OFF.\n"); digitalWrite(PIN_SSR2, LOW);
#define BACKLIGHT_ON digitalWrite(PIN_LCD_LED, HIGH);
#define BACKLIGHT_OFF digitalWrite(PIN_LCD_LED, LOW);
#define ACTUATOR_LOCK { _LOG_A("Locking Actuator.\n"); digitalWrite(PIN_ACTB, HIGH); digitalWrite(PIN_ACTA, LOW); }
#define ACTUATOR_UNLOCK { _LOG_A("Unlocking Actuator.\n"); digitalWrite(PIN_ACTB, LOW); digitalWrite(PIN_ACTA, HIGH); }
#define ACTUATOR_OFF { digitalWrite(PIN_ACTB, HIGH); digitalWrite(PIN_ACTA, HIGH); }
#define ONEWIRE_LOW { digitalWrite(PIN_SW_IN, LOW); pinMode(PIN_SW_IN, OUTPUT); } // SW set to 0, set to output (driven low)
#define ONEWIRE_HIGH { digitalWrite(PIN_SW_IN, HIGH); pinMode(PIN_SW_IN, OUTPUT); } // SW set to 1, set to output (driven high)
#define ONEWIRE_FLOATHIGH pinMode(PIN_SW_IN, INPUT_PULLUP ); // SW input (floating high)
#define RCMFAULT digitalRead(PIN_RCM_FAULT)
#define FREE(x) free(x); x = NULL;
#define FW_DOWNLOAD_PATH "http://smartevse-3.s3.eu-west-2.amazonaws.com"
#define MODBUS_INVALID 0
#define MODBUS_OK 1
#define MODBUS_REQUEST 2
#define MODBUS_RESPONSE 3
#define MODBUS_EXCEPTION 4
#define MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS 0x02
#define MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE 0x03
#define MODBUS_EVSE_STATUS_START 0x0000
#define MODBUS_EVSE_STATUS_COUNT 12
#define MODBUS_EVSE_CONFIG_START 0x0100
#define MODBUS_EVSE_CONFIG_COUNT 10
#define MODBUS_SYS_CONFIG_START 0x0200
#define MODBUS_SYS_CONFIG_COUNT 26
#define MODBUS_MAX_REGISTER_READ MODBUS_SYS_CONFIG_COUNT
#define MODBUS_BUFFER_SIZE MODBUS_MAX_REGISTER_READ * 2 + 10
// EVSE status
#define STATUS_STATE 64 // 0x0000: State
#define STATUS_ERROR 65 // 0x0001: Error
#define STATUS_CURRENT 66 // 0x0002: Charging current (A * 10)
#define STATUS_MODE 67 // 0x0003: EVSE Mode
#define STATUS_SOLAR_TIMER 68 // 0x0004: Solar Timer
#define STATUS_ACCESS 69 // 0x0005: Access bit
#define STATUS_CONFIG_CHANGED 70 // 0x0006: Configuration changed
#define STATUS_MAX 71 // 0x0007: Maximum charging current (RO)
#define STATUS_PHASE_COUNT 72 // 0x0008: Number of used phases (RO) (ToDo)
#define STATUS_REAL_CURRENT 73 // 0x0009: Real charging current (RO) (ToDo)
#define STATUS_TEMP 74 // 0x000A: Temperature (RO)
#define STATUS_SERIAL 75 // 0x000B: Serial number (RO)
// Node specific configuration
#define MENU_ENTER 1
#define MENU_CONFIG 2 // 0x0100: Configuration
#define MENU_LOCK 3 // 0x0101: Cable lock
#define MENU_MIN 4 // 0x0102: MIN Charge Current the EV will accept
#define MENU_MAX 5 // 0x0103: MAX Charge Current for this EVSE
#define MENU_LOADBL 6 // 0x0104: Load Balance
#define MENU_SWITCH 7 // 0x0105: External Start/Stop button
#define MENU_RCMON 8 // 0x0106: Residual Current Monitor
#define MENU_RFIDREADER 9 // 0x0107: Use RFID reader
#define MENU_EVMETER 10 // 0x0108: Type of EV electric meter
#define MENU_EVMETERADDRESS 11 // 0x0109: Address of EV electric meter
// System configuration (same on all SmartEVSE in a LoadBalancing setup)
#define MENU_MODE 12 // 0x0200: EVSE mode
#define MENU_CIRCUIT 13 // 0x0201: EVSE Circuit max Current
#define MENU_GRID 14 // 0x0202: Grid type to which the Sensorbox is connected
#define MENU_CAL 15 // 0x0203: CT calibration value
#define MENU_MAINS 16 // 0x0204: Max Mains Current
#define MENU_START 17 // 0x0205: Surplus energy start Current
#define MENU_STOP 18 // 0x0206: Stop solar charging at 6A after this time
#define MENU_IMPORT 19 // 0x0207: Allow grid power when solar charging
#define MENU_MAINSMETER 20 // 0x0208: Type of Mains electric meter
#define MENU_MAINSMETERADDRESS 21 // 0x0209: Address of Mains electric meter
#define MENU_EMCUSTOM_ENDIANESS 22 // 0x020D: Byte order of custom electric meter
#define MENU_EMCUSTOM_DATATYPE 23 // 0x020E: Data type of custom electric meter
#define MENU_EMCUSTOM_FUNCTION 24 // 0x020F: Modbus Function (3/4) of custom electric meter
#define MENU_EMCUSTOM_UREGISTER 25 // 0x0210: Register for Voltage (V) of custom electric meter
#define MENU_EMCUSTOM_UDIVISOR 26 // 0x0211: Divisor for Voltage (V) of custom electric meter (10^x)
#define MENU_EMCUSTOM_IREGISTER 27 // 0x0212: Register for Current (A) of custom electric meter
#define MENU_EMCUSTOM_IDIVISOR 28 // 0x0213: Divisor for Current (A) of custom electric meter (10^x)
#define MENU_EMCUSTOM_PREGISTER 29 // 0x0214: Register for Power (W) of custom electric meter
#define MENU_EMCUSTOM_PDIVISOR 30 // 0x0215: Divisor for Power (W) of custom electric meter (10^x)
#define MENU_EMCUSTOM_EREGISTER 31 // 0x0216: Register for Energy (kWh) of custom electric meter
#define MENU_EMCUSTOM_EDIVISOR 32 // 0x0217: Divisor for Energy (kWh) of custom electric meter (10^x)
#define MENU_EMCUSTOM_READMAX 33 // 0x0218: Maximum register read (ToDo)
#define MENU_WIFI 34 // 0x0219: WiFi mode
#define MENU_C2 35
#define MENU_MAX_TEMP 36
#define MENU_SUMMAINS 37
#define MENU_OFF 38 // so access bit is reset and charging stops when pressing < button 2 seconds
#define MENU_ON 39 // so access bit is set and charging starts when pressing > button 2 seconds
#define MENU_EXIT 40
#define MENU_STATE 50
#define _RSTB_0 digitalWrite(PIN_LCD_RST, LOW);
#define _RSTB_1 digitalWrite(PIN_LCD_RST, HIGH);
#define _A0_0 digitalWrite(PIN_LCD_A0_B2, LOW);
#define _A0_1 digitalWrite(PIN_LCD_A0_B2, HIGH);
#define EM_SENSORBOX 1 // Mains meter types
#define EM_PHOENIX_CONTACT 2
#define EM_FINDER_7E 3
#define EM_EASTRON3P 4
#define EM_EASTRON3P_INV 5
#define EM_ABB 6
#define EM_SOLAREDGE 7
#define EM_WAGO 8
#define EM_API 9
#define EM_EASTRON1P 10
#define EM_FINDER_7M 11
#define EM_UNUSED_SLOT1 12
#define EM_UNUSED_SLOT2 13
#define EM_UNUSED_SLOT3 14
#define EM_UNUSED_SLOT4 15
#define EM_CUSTOM 16
#define ENDIANESS_LBF_LWF 0
#define ENDIANESS_LBF_HWF 1
#define ENDIANESS_HBF_LWF 2
#define ENDIANESS_HBF_HWF 3
#define OWNER_FACT "SmartEVSE"
#define REPO_FACT "SmartEVSE-3"
#define OWNER_COMM "dingo35"
#define REPO_COMM "SmartEVSE-3.5"
typedef enum mb_datatype {
MB_DATATYPE_INT32 = 0,
MB_DATATYPE_FLOAT32 = 1,
MB_DATATYPE_INT16 = 2,
MB_DATATYPE_MAX,
} MBDataType;
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
#define RTC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define RTC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
extern String APpassword;
extern struct tm timeinfo;
extern uint16_t ICal; // CT calibration value
extern uint8_t Mode; // EVSE mode
extern uint8_t LoadBl; // Load Balance Setting (Disable, Master or Node)
extern uint8_t Grid;
extern uint8_t MainsMeterAddress;
extern uint8_t EVMeter; // Type of EV electric meter (0: Disabled / Constants EM_*)
extern uint8_t EVMeterAddress;
#if FAKE_RFID
extern uint8_t Show_RFID;
#endif
extern int16_t Irms[3]; // Momentary current per Phase (Amps *10) (23 = 2.3A)
extern int16_t Irms_EV[3]; // Momentary current per Phase (Amps *10) (23 = 2.3A)
extern uint8_t State;
extern uint8_t ErrorFlags;
extern uint8_t NextState;
extern int16_t Isum;
extern uint16_t Balanced[NR_EVSES]; // Amps value per EVSE
extern uint8_t LCDTimer;
extern uint16_t BacklightTimer; // remaining seconds the LCD backlight is active
extern uint8_t ButtonState; // Holds latest push Buttons state (LSB 2:0)
extern uint8_t OldButtonState; // Holds previous push Buttons state (LSB 2:0)
extern uint8_t LCDNav;
extern uint8_t LCDupdate;
extern uint8_t SubMenu;
extern uint32_t ScrollTimer;
extern uint8_t ChargeDelay; // Delays charging in seconds.
extern uint8_t TestState;
extern uint8_t Access_bit;
extern uint16_t CardOffset;
extern uint8_t GridActive; // When the CT's are used on Sensorbox2, it enables the GRID menu option.
extern uint8_t CalActive; // When the CT's are used on Sensorbox(1.5 or 2), it enables the CAL menu option.
extern uint16_t Iuncal;
extern uint16_t SolarStopTimer;
extern int32_t EnergyCharged;
extern int32_t EnergyCapacity;
extern int16_t PowerMeasured;
extern uint8_t RFIDstatus;
extern bool LocalTimeSet;
extern uint32_t serialnr;
extern uint8_t MenuItems[MENU_EXIT];
enum EnableC2_t { NOT_PRESENT, ALWAYS_OFF, SOLAR_OFF, ALWAYS_ON, AUTO };
enum Modem_t { NOTPRESENT, EXPERIMENT };
const static char StrEnableC2[][12] = { "Not present", "Always Off", "Solar Off", "Always On", "Auto" };
const static char StrModem[][12] = { "Not present", "Experiment" };
enum Single_Phase_t { FALSE, GOING_TO_SWITCH, AFTER_SWITCH };
extern Single_Phase_t Switching_To_Single_Phase;
extern uint8_t Nr_Of_Phases_Charging;
const struct {
char LCD[10];
char Desc[52];
uint16_t Min;
uint16_t Max;
uint16_t Default;
} MenuStr[MENU_EXIT + 1] = {
{"", "Not in menu", 0, 0, 0},
{"", "Hold 2 sec", 0, 0, 0},
// Node specific configuration
/* LCD, Desc, Min, Max, Default */
{"CONFIG", "Fixed Cable or Type 2 Socket", 0, 1, CONFIG},
{"LOCK", "Cable locking actuator type", 0, 2, LOCK},
{"MIN", "MIN Charge Current the EV will accept (per phase)", MIN_CURRENT, 16, MIN_CURRENT},
{"MAX", "MAX Charge Current for this EVSE (per phase)", 6, 80, MAX_CURRENT},
{"PWR SHARE", "Share Power between multiple SmartEVSEs (2-8)", 0, NR_EVSES, LOADBL},
{"SWITCH", "Switch function control on pin SW", 0, 4, SWITCH},
{"RCMON", "Residual Current Monitor on pin RCM", 0, 1, RC_MON},
{"RFID", "RFID reader, learn/remove cards", 0, 5, RFID_READER},
{"EV METER","Type of EV electric meter", 0, EM_CUSTOM, EV_METER},
{"EV ADDR", "Address of EV electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, EV_METER_ADDRESS},
// System configuration
/* LCD, Desc, Min, Max, Default */
{"MODE", "Normal, Smart or Solar EVSE mode", 0, 2, MODE},
{"CIRCUIT", "EVSE Circuit max Current", 10, 160, MAX_CIRCUIT},
{"GRID", "Grid type to which the Sensorbox is connected", 0, 1, GRID},
{"CAL", "Calibrate CT1 (CT2+3 will also change)", (unsigned int) (ICAL * 0.3), (unsigned int) (ICAL * 2.0), ICAL}, // valid range is 0.3 - 2.0 times measured value
{"MAINS", "Max MAINS Current (per phase)", 10, 200, MAX_MAINS},
{"START", "Surplus energy start Current (sum of phases)", 0, 48, START_CURRENT},
{"STOP", "Stop solar charging at 6A after this time", 0, 60, STOP_TIME},
{"IMPORT", "Allow grid power when solar charging (sum of phase)",0, 48, IMPORT_CURRENT},
{"MAINS MET","Type of mains electric meter", 0, EM_CUSTOM, MAINS_METER},
{"MAINS ADR","Address of mains electric meter", MIN_METER_ADDRESS, MAX_METER_ADDRESS, MAINS_METER_ADDRESS},
{"BYTE ORD","Byte order of custom electric meter", 0, 3, EMCUSTOM_ENDIANESS},
{"DATA TYPE","Data type of custom electric meter", 0, MB_DATATYPE_MAX - 1, EMCUSTOM_DATATYPE},
{"FUNCTION","Modbus Function of custom electric meter", 3, 4, EMCUSTOM_FUNCTION},
{"VOL REGI","Register for Voltage (V) of custom electric meter", 0, 65530, EMCUSTOM_UREGISTER},
{"VOL DIVI","Divisor for Voltage (V) of custom electric meter", 0, 7, EMCUSTOM_UDIVISOR},
{"CUR REGI","Register for Current (A) of custom electric meter", 0, 65530, EMCUSTOM_IREGISTER},
{"CUR DIVI","Divisor for Current (A) of custom electric meter", 0, 7, EMCUSTOM_IDIVISOR},
{"POW REGI","Register for Power (W) of custom electric meter", 0, 65534, EMCUSTOM_PREGISTER},
{"POW DIVI","Divisor for Power (W) of custom electric meter", 0, 7, EMCUSTOM_PDIVISOR},
{"ENE REGI","Register for Energy (kWh) of custom electric meter", 0, 65534, EMCUSTOM_EREGISTER},
{"ENE DIVI","Divisor for Energy (kWh) of custom electric meter", 0, 7, EMCUSTOM_EDIVISOR},
{"READ MAX","Max register read at once of custom electric meter", 3, 255, 3},
{"WIFI", "Connect to WiFi access point", 0, 2, WIFI_MODE},
{"CONTACT 2","Contactor2 (C2) behaviour", 0, sizeof(StrEnableC2) / sizeof(StrEnableC2[0])-1, ENABLE_C2},
{"MAX TEMP","Maximum temperature for the EVSE module", 40, 75, MAX_TEMPERATURE},
{"SUM MAINS","Capacity Rate limit on sum of MAINS Current (A)", 10, 600, MAX_SUMMAINS},
{"", "Hold 2 sec to stop charging", 0, 0, 0},
{"", "Hold 2 sec to start charging", 0, 0, 0},
{"EXIT", "EXIT", 0, 0, 0}
};
struct EMstruct {
uint8_t Desc[10];
uint8_t Endianness; // 0: low byte first, low word first, 1: low byte first, high word first, 2: high byte first, low word first, 3: high byte first, high word first
uint8_t Function; // 3: holding registers, 4: input registers
MBDataType DataType; // How data is represented on this Modbus meter
uint16_t URegister; // Single phase voltage (V)
int8_t UDivisor; // 10^x
uint16_t IRegister; // Single phase current (A)
int8_t IDivisor; // 10^x
uint16_t PRegister; // Total power (W) -- only used for EV/PV meter momentary power
int8_t PDivisor; // 10^x
uint16_t ERegister; // Total imported energy (kWh); equals total energy if meter doesnt support exported energy
int8_t EDivisor; // 10^x
uint16_t ERegister_Exp; // Total exported energy (kWh)
int8_t EDivisor_Exp; // 10^x
};
extern struct EMstruct EMConfig[EM_CUSTOM + 1];
struct DelayedTimeStruct {
uint32_t epoch2; // in case of Delayed Charging the StartTime in epoch2; if zero we are NOT Delayed Charging
// epoch2 is the number of seconds since 1/1/2023 00:00 UTC, which equals epoch 1672531200
// we avoid using epoch so we don't need expensive 64bits arithmetics with difftime
// and we can store dates until 7/2/2159
int32_t diff; // StartTime minus current time in seconds
};
#define EPOCH2_OFFSET 1672531200
extern struct DelayedTimeStruct DelayedStartTime;
void CheckAPpassword(void);
void read_settings();
void write_settings(void);
void setSolarStopTimer(uint16_t Timer);
void setState(uint8_t NewState);
void setAccess(bool Access);
void SetCPDuty(uint32_t DutyCycle);
uint8_t setItemValue(uint8_t nav, uint16_t val);
uint16_t getItemValue(uint8_t nav);
void ConfigureModbusMode(uint8_t newmode);
void handleWIFImode(void);
#endif

View File

@@ -1,42 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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.
*/
#ifndef __GLCD_H
#define __GLCD_H
#define GLCD_MERGE 0b00001000
#define GLCD_HIRES_FONT
#define GLCD_FULL_CHARSET
#define GLCD_ALIGN_LEFT 0
#define GLCD_ALIGN_CENTER 1
#define GLCD_ALIGN_RIGHT 2
extern void GLCDHelp(void);
extern void GLCD(void);
extern void GLCDMenu(unsigned char Buttons);
extern void GLCD_init(void);
extern void GLCD_version(void);
#endif // #ifndef __GLCD_H

View File

@@ -1,71 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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.
*/
#ifndef __EVSE_MODBUS
#define __EVSE_MODBUS
struct ModBus {
uint8_t Address;
uint8_t Function;
uint16_t Register;
uint16_t RegisterCount;
uint16_t Value;
uint8_t *Data;
uint8_t DataLength;
uint8_t Type;
uint8_t RequestAddress;
uint8_t RequestFunction;
uint16_t RequestRegister;
uint8_t Exception;
};
// definition of MBserver / MBclient class is done in evse.cpp
extern ModbusServerRTU MBserver;
extern ModbusClientRTU MBclient;
void RS485SendBuf(uint8_t *buffer, uint8_t len);
uint8_t mapModbusRegister2ItemID();
// ########################### Modbus main functions ###########################
void ModbusReadInputRequest(uint8_t address, uint8_t function, uint16_t reg, uint16_t quantity);
void ModbusReadInputResponse(uint8_t address, uint8_t function, uint16_t *values, uint8_t count);
void ModbusWriteSingleRequest(uint8_t address, uint16_t reg, uint16_t value);
void ModbusWriteMultipleRequest(uint8_t address, uint16_t reg, uint16_t *values, uint8_t count);
void ModbusException(uint8_t address, uint8_t function, uint8_t exception);
void ModbusDecode(uint8_t *buf, uint8_t len);
// ########################### EVSE modbus functions ###########################
signed int receiveMeasurement(uint8_t *buf, uint8_t pos, uint8_t Endianness, MBDataType dataType, signed char Divisor);
void requestMeasurement(uint8_t Meter, uint8_t Address, uint16_t Register, uint8_t Count);
void requestCurrentMeasurement(uint8_t Meter, uint8_t Address);
uint8_t receiveCurrentMeasurement(uint8_t *buf, uint8_t Meter, signed int *var);
//void ReadItemValueResponse(void);
//void WriteItemValueResponse(void);
//void WriteMultipleItemValueResponse(void);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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.
*/
// This is a guard condition so that contents of this file are not included
// more than once.
#ifndef UTILS_H
#define UTILS_H
extern unsigned long pow_10[10];
uint32_t MacId();
unsigned char crc8(unsigned char *buf, unsigned char len);
unsigned int crc16(unsigned char *buf, unsigned char len);
void sprintfl(char *str, const char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal);
unsigned char triwave8(unsigned char in);
unsigned char scale8(unsigned char i, unsigned char scale);
unsigned char ease8InOutQuad(unsigned char i);
#endif /* UTILS_H */

View File

@@ -1,45 +0,0 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@@ -1,29 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1.
2.
3.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Arduino Information:**
- OS: [e.g. Windows, MacOS, Linux]
- IDE [e.g. Arduino IDE, Eclipse, VSCode]
- IDE Version [e.g. 1.8.6]
- Board [e.g ESP32]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1 +0,0 @@
.DS_Store

View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Joao Lopes
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.

View File

@@ -1,737 +0,0 @@
# RemoteDebug Library
A library for Arduino to debug projects over WiFi, with web app or telnet client,
with Print commands like Serial Monitor.
![logo](extras/readme_media/logo.png)
[![arduino-library-badge](https://www.ardu-badge.com/badge/RemoteDebug.svg?)](https://www.ardu-badge.com/RemoteDebug)
[![GitHub release](https://img.shields.io/github/release/JoaoLopesF/RemoteDebug.svg)](#releases)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/3eadfd19246f4808907cf53599a6b9f0)](https://www.codacy.com/app/JoaoLopesF/RemoteDebug?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=JoaoLopesF/RemoteDebug&amp;utm_campaign=Badge_Grade)
[![platform badge](https://img.shields.io/badge/platform-Arduino|Espressif-orange.svg)](https://github.com/arduino)
[![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/JoaoLopesF/RemoteDebug/blob/master/LICENSE.txt)
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](#github)
[![GitHub issues](https://img.shields.io/github/issues/JoaoLopesF/RemoteDebug.svg)](http://github.com/JoaoLopesF/RemoteDebug/issues)
[![star this repo](http://githubbadges.com/star.svg?user=JoaoLopesF&repo=RemoteDebug)](http://github.com/JoaoLopesF/RemoteDebug)
<!-- ![build badge](https://img.shields.io/github/stars/JoaoLopesF/RemoteDebug.svg?style=social) -->
![remotedebugapp](extras/readme_media/remotedebugapp.png)
## A library to remotely debug over a WiFi connection by telnet or web browser
### RemoteDebug setup a TCP/IP server, that you connect to debugging, as an alternative to the serial connection
## Contents
- [About](#about)
- [How it looks](#how-it-looks)
- [Github](#github)
- [News](#news)
- [Benefits](#benefits)
- [HTML5 web app](#web-app)
- [Telnet client](#telnet)
- [Wishlist](#wishlist)
- [Install](#install)
- [Using](#usage)
- [Known issues](#known-issues)
- [Releases](#releases)
- [Thanks](#thanks)
## About
By default the Arduino only has as debug possibility via the Serial port.
This has a few disadvantages:
- requires a physical cable to the Arduino device (if the device is far away or in a remote location this is not easy)
- debugging multiple Arduinos at the same time requires many serial ports and a lot of cables
With the ESP8266 (NodeMCU) or ESP32 we now have network connectivity (WiFi) which can be used for streaming debugging information in real-time.
This library is good for IoT projects, home automation, mobile robots (can debug it in moviment with a cable ?) or
another WiFi projects.
In fact, this library was born of a need to debug an IoT project of home automation.
In this project there was a central module and three auxiliary modules,
and these were far from each other. One was hard to reach, under the roof of the house.
To debug this project, accompanying the exchange of messages in realtime,
is impossible to do with traditional way, by USB cable.
The MiP_ESP8266_Library and my ESP32 WiFi robot are example of projects that uses __RemoteDebug__.
See it in: [MiP_ESP8266_Library](https://github.com/Tiogaplanet/MiP_ESP8266_Library) and [ESPlorer_v1](https://github.com/JoaoLopesF/ESPlorer_v1)
__RemoteDebug__ is improved with client buffering (is last send is <= 10ms),
to avoid mysterious delays of WiFi networking on ESP32 and ESP8266 boards
Note: If your project not use WiFi, you can use my another library,
the __[SerialDebug](https://github.com/JoaoLopesF/SerialDebug)__ library,
this library works with any Arduino board.
Note II: __RemoteDebug__ library is now only to Espressif boards, as ESP32 and ESP8266,
If need for another WiFi boards, please add an issue about this
and we will see if it is possible made the port for your board.
## How it looks
Image: In RemoteDebugApp (web app)
![webapp](extras/readme_media/remotedebug_webapp.png)
Image: In telnet client
![remotedebug_v2](extras/readme_media/remotedebug_v2.png)
Youtube (RemoteDebug v2):
[![youtube1](https://img.youtube.com/vi/T4nxdsFUGgg/0.jpg)](https://youtu.be/T4nxdsFUGgg)
Youtube (3 telnet connections with RemoteDebug) v1:
[![youtube2](http://img.youtube.com/vi/lOo-MAD8gPo/0.jpg)](http://www.youtube.com/watch?v=lOo-MAD8gPo)
## Github
Contribute to this library development by creating an account on GitHub.
Please give a star, if you find this library useful,
this help an another people, discover it too.
Please add an issue for problems or suggestion.
## News
- RemoteDebugApp Beta
- Now have another repository, [RemoteDebugApp](https://github.com/JoaoLopesF/RemoteDebugApp)
It is for local copy of web app in internet.
It is updated with lastest version of web app,
after it is publised in web server: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp/).
Download it, for use when internet is offline.
As it is a local copy, the app will check for new versions periodically.
- An HTML5 web app to use for debugging in web browser, instead telnet client,
that uses web socket to comunicate.
- Now RemoteDebug v3 have a web socket server too,
to support the RemoteDebugApp connection.
- RemoteDebugApp is in beta,
if you have any problems or suggestions, please add issue about this.
- The telnet connection remains, to any want this,
or to internet offline uses.
- Version 2.1.1
- Now __RemoteDebug__ have a code converter, for help you to convert your codes:
to do it, please access the [RemoteDebugConverter](https://github.com/JoaoLopesF/RemoteDebugConverter)
- Version 2.0.0
- Now __RemoteDebug__ can have the same simple software debugger, that __SerialDebug__ library have.
This is done, installing another library, the __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
The __RemoteDebugger__ act as an add on to __RemoteDebug__.
To support this addon, the changes in __RemoteDebug__, is minimum, just a few callbacks
It is done to no add extra overhead to projects that no need an debugger.
To more informations please access the __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__ github repository.
- Now __RemoteDebug__ have a new color system, using more colors, as done in __SerialDebugApp__
Note: due the __RemoteDebug__ library, is migrate to Arduino 1.5 format, with folder "src",
please delete and reinstall the library to avoid duplication of RemoteDebug sources files.
- Version 1.5.*
In 1.5.0 version, we have debug* and rdebug* macros (see below), that put automatically,
the name of function that called, and core id (core id is only for ESP32)
## Benefits
__SerialDebug__ is better than Arduino default debugging by Serial.print commands:
### This is more __optimized__
Being or not debugging via USB cable,
the Serial.print command allways is processed,
waste CPU time on microcontroller.
In other words, the debug commands are processed,
with someone connected in the serial or not.
With __RemoteDebug__, all debug output is processed only
if exists anyone debugging via telnet or web app connection.
And with the debug levels of resource, the volume displayed
of messages are reduced for higher levels.
For example, only process all messages,
if the level is the lowest, the verbose,
__RemoteDebug__ is otimized to reduce overheads,
in CPU and memory and include client buffering feature.
### Have __debug levels__
During the development, we can put a lot of debug messages...
But with __RemoteDebug__, we can put a level in each one.
For all messages (except levels always (debugA) or error (debugE),
the message only is processed and showed,
if debug level is equal or higher than it level
__RemoteDebug__ have 6 debug levels, in order of priority:
Alway showed:
__Error__: Critical errors
__Always__: Important messages
Another levels (showed if level is equal or higher that actual one):
__Warning__: Error conditions but not critical
__Info__: Information messages
__Debug__: Extra information
__Verbose__: More information than the usual
So We can change the level to verbose, to see all messages.
Or to debug to see only debug or higher level, etc.
Is very good to reduce a quantity of messages that a project can generate,
to help debugging.
### It is __easy__ to migrate
__RemoteDebug__ have a converter to help migrate your Arduino codes,
from Serial.prints to this library.
[RemoteDebugConverter](https://github.com/JoaoLopesF/RemoteDebugConverter)
Even if you want to do this manually, it's very simple. Please see topic [Using](#usage) above.
### Have __auto__ function name and simple __profiler__
A simple debug:
```cpp
debugV("* Run time: %02u:%02u:%02u (VERBOSE)", mRunHours, mRunMinutes, mRunSeconds);
````
Can generate this output in serial monitor:
(V p:3065 loop C1) * Run time: 00:41:23 (VERBOSE)
Where: V: is the level
p: is a profiler time, elased, between this and previous debug
loop: is a function name, that executed this debug
C1: is a core that executed this debug (and a function of this) (only for ESP32)
The remaining is the message formatted (printf)
For ESP32, the core id in each debug is very good to optimizer multicore programming.
### Have __commands__ to execute from telnet or web app
For example:
- Show help (__?__)
- Change the level of debug (__v__,__d__,__i__,__w__,__e__),
to show less or more messages.
- See memory (__m__)
- Reset the board (__reset__)
See about __RemoteDebug__ commands below.
You can add your own commands, see the examples please
If your project have __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__ installed,
have a new commands, e.g. call a function, see/change variables, ...
### Have a simple __software debugger__
Now __RemoteDebug__ (version >= 2.0.0), have an simple software debuggger,
based in codes of SerialDebug library.
This is another library, that act as an addon to __RemoteDebug__.
Please acess the RemoteDebugger repository to more informations: __[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
### Ready for __production__ (release compiler)
For release your device, just uncomment DEBUG_DISABLED in your project
Done this, and no more debug processing.
And better for DEBUG_DISABLED, __RemoteDebug__ have ZERO overhead,
due is nothing of this is compiled.
## Web app
As SerialDebug, now RemoteDebug (v3) have an app,the RemoteDebugApp,
to debug in web browser.
This app is an HTM5 web app, with websocket to comunicate to Arduino board.
For it, RemoteDebug v3 have a web socket server (can be disabled).
It used a local copy of [arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets) library,
due it not in Arduino Library manager.
As a large web page on web server, the solution for Arduino is save it in a storage,
like SPIFFS. But not have automatically updates new version in data saved this way,
this SPIFFS data is good for a project but not for a library.
Due it, this app not is stored and served by board,
instead the app is in web: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp)
Note: this not uses SSL (https), due web server socket on Arduino, not supports SSL (wss).
But after page load, all traffic is in local network, no data is exposed on internet.
The RemoteDebugApp is a modern HTML5 and needs a modern browsers to work.
Internet Explorer 11 and Safari 10 are an examples that not supported.
But you can use anothers, as Chrome, Edge, Firefox.
The web app is in beta, please add an issue,
for problems or suggestions.
Now have another repository, [RemoteDebugApp](https://github.com/JoaoLopesF/RemoteDebugApp)
It is for local copy of web app in internet.
It is updated with lastest version of web app,
after it is publised in web server: [http://joaolopesf.net/remotedebugapp](http://joaolopesf.net/remotedebugapp/).
Download it, for use when internet is offline.
As it is a local copy, the app will check for new versions periodically,
for you can download a new version.
The telnet remains work, for when want this,
or for fails on web app.
## Telnet
Telnet is a standard way of remotely connecting to a server and
is supported on all operating systems (Windows, Mac, Linux...).
MacOSx and Linux have a native telnet client.
For Windows, a typical telnet client is the __Putty__: [putty](https://www.putty.org/) .
Have a good tool for mobiles: the __Fing__, please find it in your mobile store.
Its show all devices in local network (WiFi), show ports opened and can execute the telnet client too (external App)
__RemoteDebug__ sets-up a telnet server which is listening to any telnet client that wants to connect. After connection, logging is streamed to the telnet client.
__RemoteDebug__ is very simple to use, after a few lines of initialization code, you can use the well-known "print" commands to stream your logging to the remote client.
### Debug levels
__RemoteDebug__ supports the filtering of logging based on __debug levels__:
Only show for it actual debug level:
- Verbose
- Debug
- Info
- Warnings
Note: These levels are in the order of most-logging -> least-logging.
Or for always show (not depends of actual debug level):
- Any
- Errors
Note: All debugs is processed and showed only if have a client connection.
The telnet client or web app can set the debug level by typing a few simple commands.
### Profiler
__RemoteDebug__ includes a simple profiler. It can be enabled by the connected client (telnet or web app)
or the Arduino code itself.
When enabled, it shows the time between 2 debug statements, using different colors depending on the elapsed time.
A typical example would be to insert logging just before and after a function after which you can see how much the is spent in the function.
### Lightweight
__RemoteDebug__ is designed to give minimal overhead (connected or not) and
only process debugs,if there is a client (telnet or web app) connected.
### Custom commands
__RemoteDebug__ supports custom commands that can be entered in the client (telnet or web app).
These trigger the execution of a custom function in the Arduino code. For example this can be used to send back a status on request of the client.
### DISCLAIMER
The current version of __RemoteDebug__ does not yet include any encrypted authentication,
only plain text and is intended only for development, not use in production/release.
Future versions, if is possible, will include a secure way for authentication and further testing to support production environments.
## Wishlist
- An app to RemoteDebug like SerialDebug have.
- Http page to begin/stop the telnet server or websocket server.
- Authentication as telnet support (kerberos, etc.) to support production environment
## Install
Just download or clone this repository.
Or for Arduino IDE, you can use the library manager to install and update the library.
<!-- For install help, please see: [https://www.arduino.cc/en/Guide/Libraries](https://www.arduino.cc/en/Guide/Libraries) -->
For install help, please click on this: [![arduino-library-badge](https://www.ardu-badge.com/badge/RemoteDebug.svg?)](https://www.ardu-badge.com/RemoteDebug)
<!--![install](extras/readme_media/install.png)-->
For another IDE, or not using the library manager of Arduino IDE,
I suggest you use a [Github Desktop](https://desktop.github.com/) app to clone,it help to keep updated.
Please open the projects in example folder, to see it working.
## Usage
### includes
```cpp
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
```
### instance
RemoteDebug Debug;
### setup
In the setup function after WiFi initialization
```cpp
// Initialize the server (telnet or web socket) of RemoteDebug
Debug.begin(HOST_NAME);
// OR
Debug.begin(HOST_NAME, startingDebugLevel);
// Options
Debug.setResetCmdEnabled(true); // Enable the reset command
// Debug.showProfiler(true); // To show profiler - time between messages of Debug
```
Note: to enable the debugger, by RemoteDebugger, please acess this github repository:
__[RemoteDebugger](https://github.com/JoaoLopesF/RemoteDebugger)__
In the tail of loop function
```cpp
// Remote debug over WiFi
Debug.handle();
// Or
debugHandle(); // Equal to SerialDebug
```
In any place of you code:
```cpp
#ifndef DEBUG_DISABLED
if (Debug.isActive(Debug.<level>)) {
Debug.printf("bla bla bla: %d %s", number, str); // OR
Debug.printf("bla bla bla: %d %s", number, str.c_str()); // Note: if type is String need c_str() // OR
Debug.println("bla bla bla 2 ln");
Debug.printf("float: %f\n", value); // Not works in ESP8266 :-(
// Note: to show floats with printf (ESP8266 only),
// you can use my ArduinoUtil library -> https://github.com/JoaoLopesF/ArduinoUtil
Debug.printf("float: %s\n", Util.formatFloat(value, 0, 5).c_str());
}
#endif
```
Note: Using isActive, you need surround the code by DEBUG_DISABLE precompile condition,
to avoid compile it for production/release
Or short way (equal to SerialDebug) (prefered if only one debug at time):
```cpp
debugA("This is a any (always showed) - var %d", var);
debugV("This is a verbose - var %d", var);
debugD("This is a debug - var %d", var);
debugI("This is a information - var %d", var);
debugW("This is a warning - var %d", var);
debugE("This is a error - var %d", var);
debugV("This is a println");
```
Or if your project uses several Serial.print commands to generate a single debug message
for example:
```cpp
Serial.print("a = ");
Serial.print(a);
Serial.print(" b = ");
Serial.print(b);
Serial.print(" c = ");
Serial.println(c);
```
can be use rdebug* macros:
```cpp
rdebugV("a = ");
rdebugV(a);
rdebugV(" b = ");
rdebugV(b);
rdebugV(" c = ");
rdebugVln(c);
```
Note: in future, I suggest that you migrate this to a single debug command:
```cpp
debugV(a = %d b = %d c = %d", a, b, c);
```
An example of use debug levels: (supposing the data is a lot of characters)
```cpp
if (Debug.isActive(Debug.VERBOSE)) { // Debug message long
Debug.printf("routine: data received: %s\n", data.c_str()); // Note: if type is String need c_str()
} else if (Debug.isActive(Debug.DEBUG)) { // Debug message short
Debug.printf("routine: data received: %s ...\n", data.substring(0, 20).c_str()); // %.20s not working :-|
}
```
Starting at version 1.5.0, debug macros (debug* and rdebug*), automatically put the name of function that called the macro,
and core id (core id only for ESP32).
So:
```cpp
void foo() {
uint8_t var = 1;
debugV("this is a debug - var %u", var);
}
```
It will show in client (telnet or web app):
(V p:^0000ms) (foo)(C1) this is a debug - var 1
Where:
V -> verbose
p -> profiler time
(foo) -> this is a function name that calls the debug macro
(C1) -> It is running it Core 1 (only for ESP32)
An example of use debug with serial enabled
Useful to see messages if setup or
in cause the ESP8266/ESP32 is rebooting (client connection stop before received all messages)
Only for this purposes I suggest it
```cpp
// Setup after Debug.begin
Debug.setSerialEnabled(true); // All messages too send to serial too, and can be see in serial monitor
```
For reduce overheads RemoteDebug is disconnect the client (telnet or web app), if it not active.
- Please press enter or any key if you need keep the connection
- The default is 5 minutes (You can change it in RemoteDebug.h)
- You can use mDNS to register each node with different name, it helps to connect without know the IP.
Please not forget to use if clause with Debug.isActive (if not using debug macros)
---> This is very important to reduce overheads and work of debug levels
Please see the samples, basic or advanced, to learn how to use
In advanced sample, I used WifiManager library, ArduinoOTA and mDNS, please see it.
## Releases
### 3.0.5 - 2019-03-23
- Ajustment on debugA macro, thanks @jetpax and @cmidgley to add this issue.
### 3.0.4 - 2019-03-19
- All public configurations (#defines) have moved to RemoteDebugCfg.h, to facilitate changes for anybody.
- Changed examples, with warnings on change any #define in project,
with workarounds if it not work. (thanks to @22MarioZ for added this issue)
### 3.0.3 - 2019-03-18
- Adjustments if web socket is disabled
### 3.0.2 - 2019-03-16
- Adjustments in examples, added one for debugger
### 3.0.1 - 2019-03-13
- Adjustments in silente mode
- Commands from RemoteDebugApp now is treated
- Adjusts to RemoteDebugger support connection by web sockets
### 3.0.0 - 2019-03-10
- If not disabled, add a web socket server to comunicate with RemoteDebugApp (HTML5 web app)
- The standard telnet still working, to debug with internet offline
- Ajustment on debugA macro, thanks @jetpax to add this issue
### 2.1.2 - 2019-03-08
- Add empty rprint* macros, if debug is disabled
### 2.1.1 - 2019-03-06
- Create option DEBUG_DISABLE_AUTO_FUNC
- Create macros to be used for code converter: rprint and rprintln
RemoteDebug now have an code converters to help migrate codes
### 2.1.0 - 2019-03-04
- Create precompiler DEBUG_DISABLED to compile for production/release,
equal that have in SerialDebug
- Adjustments in examples
### 2.0.1 - 2019-03-01
- Adjustments for the debugger: it still disable until dbg command, equal to SerialDebug
- The callback will to be called before print debug messages now
- And only if debugger is enabled in RemoteDebugger (command dbg)
- Changed handle debugger logic
### 2.0.0 - 2019-02-28
- Added support to RemoteDebug addon library: the RemoteDebugger, an simple software debugger, based on SerialDebug
- New color system
### 1.5.9 - 2019-02-18
- Bug -> sometimes the command is process twice
- Workaround -> check time
### 1.5.8 - 2019-02-08
- New macros to compatibility with SerialDebug (can use RemoteDebug or SerialDebug) thanks to @phrxmd
### 1.5.7 - 2018-11-03
- Fixed bug for MAX_TIME_INACTIVE, thanks to @achuchev to add this issue
### 1.5.6 - 2018-10-19
- Adjustments based on pull request from @jeroenst (to allow serial output with telnet password and setPassword method)
### 1.5.5 - 2018-10-19
- Serial output is now not allowed if telnet password is enabled
- Few adjustments
### 1.5.4 - 2018-10-05
- Few adjustment in write logic
### 1.5.3 - 2018-09-04
- Serial output adjustments (due bug in password logic)
### 1.5.2
- Correct rdebug macro (thanks @stritti)
### 1.5.1 - 2018-08-28
- New silent mode (command s)
### 1.5.0 - 2018-08=26
- Auto function name and ESP32 core id for rdebug* macros
- begin method have a option for port number
- Few adjustments
- Added new rdebug?ln to put auto new line
### 1.4.0 - 2018-08-18
- Simple text password request feature (disabled by default)
Notes:
It is very simple feature, only text, no cryptography,
and the password is echoed in screen (I not discovery yet how disable it)
telnet use advanced authentication (kerberos, etc.)
Such as now RemoteDebug is not for production (releases),
this kind of authentication will not be done now.
### 1.3.1 - 2018-08-18
- Adjustments in precompiler macros
### 1.3.0 - 2018-08-17
- Bug in write with latest ESP8266 SDK
- Port number can be modified in project Arduino (.ino file)
- Few adjustments as ESP32 includes
### 1.2.2
- Adjustments, as avoid ESP32 include errors
- Telnet port of server can be modified by project
Just put it in your .ino, before the include:
### 1.2.0
- Shortcuts and client buffering to avoid mysterious delay of ESP networking
### 1.1.0
- Adjustments and now runs in Esp32 too.
### 1.0.0
- Adjustments and improvements from Beta versions.
New features:
- Filter
- Colors
- Support to Windows telnet client
### 0.9
- First Beta
## Known issues
- Sometimes (rarely) the connection over telnet becomes very slow.
Especially right after uploading firmware.
Reset command in telnet connection or turn off/on can be resolve it.
But I need find why it occurs
## Thanks
First thanks a lot for Igrr for bring to us the Arduino ESP8266 and to Espressif to Arduino ESP32
Thanks to Links2004 for a good web server socket, used for web app connection.
For the logo: thanks to a freepik and pngtree sites for free icons that have in logo
Resources:
- Example of TelnetServer code in http://www.rudiswiki.de/wiki9/WiFiTelnetServer
- arduinoWebSockets library in https://github.com/Links2004/arduinoWebSockets
## End of README
Hit counter on this file, starting at 2019-03-03:
[![HitCount](http://hits.dwyl.io/JoaoLopesF/RemoteDebug.svg)](http://hits.dwyl.io/JoaoLopesF/RemoteDebug)

View File

@@ -1,634 +0,0 @@
////////
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
// Author : Joao Lopes
// File : RemoteDebug_Advanced.ino
// Notes :
//
// Attention: This library is only for help development. Please not use this in production
//
// Sample to show how to use advanced features of Arduino and RemoteDebug library
//
// Example of use:
//
//#ifndef DEBUG_DISABLED
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
// Debug.printf("bla bla bla: %d %s\n", number, str);
// Debug.println("bla bla bla");
// }
//#endif
//
// Or short way (prefered if only one debug at time)
//
// debugA("This is a any (always showed) - var %d", var);
//
// debugV("This is a verbose - var %d", var);
// debugD("This is a debug - var %d", var);
// debugI("This is a information - var %d", var);
// debugW("This is a warning - var %d", var);
// debugE("This is a error - var %d", var);
//
// debugV("This is println");
//
///////
////// Defines
// Host name (please change it)
#define HOST_NAME "remotedebug"
// Board especific libraries
#if defined ESP8266 || defined ESP32
// Use mDNS ? (comment this do disable it)
#define USE_MDNS true
// Arduino OTA (uncomment this to enable)
//#define USE_ARDUINO_OTA true
#else
// RemoteDebug library is now only to Espressif boards,
// as ESP32 and ESP82266,
// If need for another WiFi boards,
// please add an issue about this
// and we will see if it is possible made the port for your board.
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
#error "The board must be ESP8266 or ESP32"
#endif // ESP
// Web server (uncomment this to need this)
//#define WEB_SERVER_ENABLED true
////// Includes
#if defined ESP8266
// Includes of ESP8266
#include <ESP8266WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include <ESP8266mDNS.h>
#endif
#ifdef WEB_SERVER_ENABLED
#include <ESP8266WebServer.h>
#endif
#elif defined ESP32
// Includes of ESP32
#include <WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include "ESPmDNS.h"
#endif
#ifdef WEB_SERVER_ENABLED
#include <WebServer.h>
#endif
#else
#error "For now, RemoteDebug support only boards Espressif, as ESP8266 and ESP32"
#endif // ESP
// Arduino OTA
#ifdef USE_ARDUINO_OTA
#include <ArduinoOTA.h>
#endif
// HTTP Web server
#ifdef WEB_SERVER_ENABLED
#if defined ESP8266
ESP8266WebServer HTTPServer(80);
#elif defined ESP32
WebServer HTTPServer(80);
#endif
#endif // WEB_SERVER_ENABLED
///// Remote debug over WiFi - not recommended for production/release, only for development
// Options for RemoteDebug of this project
// Attention: read this, before you change any option
//
// If yot changed it and not works, the compiler is using catching old compiled files
// To workaround this:
// - If have a clean project option in IDE (as Eclipse/Platformio), do it
// - or force compiler to compiler all (changing any configuration of board)
// - or to this change globally in RemoteDebugCfg.h (on library directory)
// - And upload again
//
// thanks to @22MarioZ for added this issue
// Disable all debug ?
// Important to compile for prodution/release
// Disable all debug ? Good to release builds (production)
// as nothing of RemoteDebug is compiled, zero overhead :-)
// Uncomment the line below, to do it:
//#define DEBUG_DISABLED true
// Disable te auto function feature of RemoteDebug
// Good if your code already have func name on debug messages
// Uncomment the line below, to do it:
//#define DEBUG_DISABLE_AUTO_FUNC true
// Disable Websocket? This is used with RemoteDebugApp connection
// Uncomment the line below, to do it:
//#define WEBSOCKET_DISABLED true
#ifndef WEBSOCKET_DISABLED // Only if Web socket enabled (RemoteDebugApp)
// If enabled, you can change the port here (8232 is default)
// Uncomment the line below, to do it:
//#define WEBSOCKET_PORT 8232
// Internally, the RemoteDebug uses a local copy of the arduinoWebSockets library (https://github.com/Links2004/arduinoWebSockets)
// Due it not in Arduino Library Manager
// If your project already use this library,
// Uncomment the line below, to do it:
//#define USE_LIB_WEBSOCKET true
#endif
// Include libraries
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
#ifndef DEBUG_DISABLED // Only if debug is not disabled (for production/release)
// Instance of RemoteDebug
RemoteDebug Debug;
#endif
// WiFi credentials
// Note: if commented, is used the smartConfig
// That allow to it in mobile app
// See more details in http://www.iotsharing.com/2017/05/how-to-use-smartconfig-on-esp32.html
//#define WIFI_SSID "..." // your network SSID (name)
//#define WIFI_PASS "..." // your network key
/////// Variables
// Time
uint32_t mTimeToSec = 0;
uint32_t mTimeSeconds = 0;
////// Setup
void setup() {
// Initialize the Serial (use only in setup codes)
Serial.begin(230400);
// Buildin led
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
#endif
// Connect WiFi
connectWiFi();
// Host name of WiFi
#ifdef ESP8266
WiFi.hostname(HOST_NAME);
#endif
#ifdef USE_ARDUINO_OTA
// Update over air (OTA)
initializeOTA();
#endif
// Register host name in mDNS
#if defined USE_MDNS && defined HOST_NAME
if (MDNS.begin(HOST_NAME)) {
Serial.print("* MDNS responder started. Hostname -> ");
Serial.println(HOST_NAME);
}
// Register the services
#ifdef WEB_SERVER_ENABLED
MDNS.addService("http", "tcp", 80); // Web server
#endif
#ifndef DEBUG_DISABLED
MDNS.addService("telnet", "tcp", 23); // Telnet server of RemoteDebug, register as telnet
#endif
#endif // MDNS
// HTTP web server
#ifdef WEB_SERVER_ENABLED
HTTPServer.on("/", handleRoot);
HTTPServer.onNotFound(handleNotFound);
HTTPServer.begin();
Serial.println("* HTTP server started");
#endif
#ifndef DEBUG_DISABLED // Only for development
// Initialize RemoteDebug
Debug.begin(HOST_NAME); // Initialize the WiFi server
//Debug.setPassword("r3m0t0."); // Password for WiFi client connection (telnet or webapp) ?
Debug.setResetCmdEnabled(true); // Enable the reset command
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
Debug.showColors(true); // Colors
// Debug.setSerialEnabled(true); // if you wants serial echo - only recommended if ESP is plugged in USB
// Project commands
String helpCmd = "bench1 - Benchmark 1\n";
helpCmd.concat("bench2 - Benchmark 2");
Debug.setHelpProjectsCmds(helpCmd);
Debug.setCallBackProjectCmds(&processCmdRemoteDebug);
// End of setup - show IP
Serial.println("* Arduino RemoteDebug Library");
Serial.println("*");
Serial.print("* WiFI connected. IP address: ");
Serial.println(WiFi.localIP());
Serial.println("*");
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
Serial.println("*");
Serial.println("* This sample will send messages of debug in all levels.");
Serial.println("*");
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
Serial.println("*");
#endif
}
void loop() {
#ifndef DEBUG_DISABLED
// Time of begin of this loop
uint32_t timeBeginLoop = millis();
#endif
// Each second
if (millis() >= mTimeToSec) {
// Time
mTimeToSec = millis() + 1000;
mTimeSeconds++;
// Blink the led
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
// Debug the time (verbose level)
debugV("* Time: %u seconds (VERBOSE)", mTimeSeconds);
if (mTimeSeconds % 5 == 0) { // Each 5 seconds
// Debug levels
debugV("* This is a message of debug level VERBOSE");
debugD("* This is a message of debug level DEBUG");
debugI("* This is a message of debug level INFO");
debugW("* This is a message of debug level WARNING");
debugE("* This is a message of debug level ERROR");
// RemoteDebug isActive? Use this RemoteDebug sintaxe if you need process anything only for debug
// It is good to avoid overheads (this is only use that is suggest to use isActive)
// Note this need be surrounded by DEBUG_DISABLED precompiler condition to not compile for production/release
#ifndef DEBUG_DISABLED
if (Debug.isActive(Debug.VERBOSE)) {
debugV("Calling a foo function");
debugV("At time of %d sec.\n", mTimeSeconds);
// Call a function
foo();
}
#endif
}
}
////// Services on Wifi
#ifdef USE_ARDUINO_OTA
// Update over air (OTA)
ArduinoOTA.handle();
#endif
#ifdef WEB_SERVER_ENABLED
// Web server
HTTPServer.handleClient();
#endif
#ifndef DEBUG_DISABLED
// RemoteDebug handle (for WiFi connections)
Debug.handle();
#endif
// Give a time for ESP
yield();
#ifndef DEBUG_DISABLED
// Show a debug - warning if time of these loop is over 50 (info) or 100 ms (warning)
uint32_t time = (millis() - timeBeginLoop);
if (time > 100) {
debugI("* Time elapsed for the loop: %u ms.", time);
} else if (time > 200) {
debugW("* Time elapsed for the loop: %u ms.", time);
}
#endif
}
// Function example to show a new auto function name of debug* macros
void foo() {
uint8_t var = 1;
debugV("this is a debug - var %u", var);
debugV("This is a println");
}
#ifndef DEBUG_DISABLED
// Process commands from RemoteDebug
void processCmdRemoteDebug() {
String lastCmd = Debug.getLastCommand();
if (lastCmd == "bench1") {
// Benchmark 1 - Printf
debugA("* Benchmark 1 - one Printf");
uint32_t timeBegin = millis();
uint8_t times = 50;
for (uint8_t i = 1; i <= times; i++) {
debugA("%u - 1234567890 - AAAA", i);
}
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
(millis() - timeBegin));
} else if (lastCmd == "bench2") {
// Benchmark 2 - Print/println
debugA("* Benchmark 2 - Print/Println");
uint32_t timeBegin = millis();
uint8_t times = 50;
for (uint8_t i = 1; i <= times; i++) {
if (Debug.isActive(Debug.ANY)) {
Debug.print(i);
Debug.print(" - 1234567890");
Debug.println(" - AAAA");
}
}
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
(millis() - timeBegin));
}
}
#endif
////// WiFi
void connectWiFi() {
////// Connect WiFi
#ifdef EM_DEPURACAO
Serial.println("*** connectWiFi: begin conection ...");
#endif
#ifdef ESP32
// ESP32 // TODO: is really necessary ?
WiFi.enableSTA(true);
delay(100);
#endif
// Connect with SSID and password stored
#ifndef WIFI_SSID
WiFi.begin();
#else
WiFi.begin(WIFI_SSID, WIFI_PASS);
#endif
// Wait connection
uint32_t timeout = millis() + 20000; // Time out
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
delay(250);
Serial.print(".");
}
// Not connected yet?
if (WiFi.status() != WL_CONNECTED) {
#ifndef WIFI_SSID
// SmartConfig
WiFi.beginSmartConfig();
// Wait for SmartConfig packet from mobile
Serial.println("connectWiFi: Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("connectWiFi: SmartConfig received.");
// Wait for WiFi to connect to AP
Serial.println("connectWiFi: Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
#else
Serial.println("Not possible connect to WiFi, rebooting");
ESP.restart();
#endif
}
// End
Serial.println("");
Serial.print("connectWiFi: connect a ");
Serial.println(WiFi.SSID());
Serial.print("IP: ");
Serial.println(WiFi.localIP().toString());
}
#ifdef USE_ARDUINO_OTA
// Initialize o Arduino OTA
void initializeOTA() {
// TODO: option to authentication (password)
#if defined ESP8266
ArduinoOTA.onStart([]() {
Serial.println("* OTA: Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\n*OTA: End");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("*OTA: Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
#elif defined ESP32
// ArduinoOTA
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
Serial.println("Start updating " + type);
}).onEnd([]() {
Serial.println("\nEnd");
}).onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
}).onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
#endif
// Begin
ArduinoOTA.begin();
}
#endif
#ifdef WEB_SERVER_ENABLED
/////////// Handles
void handleRoot() {
// Root web page
HTTPServer.send(200, "text/plain", "hello from esp - RemoteDebug Sample!");
}
void handleNotFound(){
// Page not Found
String message = "File Not Found\n\n";
message.concat("URI: ");
message.concat(HTTPServer.uri());
message.concat("\nMethod: ");
message.concat((HTTPServer.method() == HTTP_GET)?"GET":"POST");
message.concat("\nArguments: ");
message.concat(HTTPServer.args());
message.concat("\n");
for (uint8_t i=0; i<HTTPServer.args(); i++){
message.concat(" " + HTTPServer.argName(i) + ": " + HTTPServer.arg(i) + "\n");
}
HTTPServer.send(404, "text/plain", message);
}
#endif
/////////// End

View File

@@ -1,244 +0,0 @@
////////
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
// Author : Joao Lopes
// File : RemoteDebug_Basic.ino
// Notes :
//
// Attention: This library is only for help development. Please not use this in production
//
// First sample to show how to use it - basic one
//
// Example of use:
//
//#ifndef DEBUG_DISABLED
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
// Debug.printf("bla bla bla: %d %s\n", number, str);
// Debug.println("bla bla bla");
// }
//#endif
//
// Or short way (prefered if only one debug at time)
//
// debugA("This is a any (always showed) - var %d", var);
//
// debugV("This is a verbose - var %d", var);
// debugD("This is a debug - var %d", var);
// debugI("This is a information - var %d", var);
// debugW("This is a warning - var %d", var);
// debugE("This is a error - var %d", var);
//
// debugV("This is println");
//
//
///////
////// Defines
// Host name (please change it)
#define HOST_NAME "remotedebug"
// Board especific libraries
#if defined ESP8266 || defined ESP32
// Use mDNS ? (comment this do disable it)
#define USE_MDNS true
// Arduino OTA (uncomment this to enable)
//#define USE_ARDUINO_OTA true
#else
// RemoteDebug library is now only to Espressif boards,
// as ESP32 and ESP82266,
// If need for another WiFi boards,
// please add an issue about this
// and we will see if it is possible made the port for your board.
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
#error "The board must be ESP8266 or ESP32"
#endif // ESP
//////// Libraries
#if defined ESP8266
// Includes of ESP8266
#include <ESP8266WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include <ESP8266mDNS.h>
#endif
#elif defined ESP32
// Includes of ESP32
#include <WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include "ESPmDNS.h"
#endif
#endif // ESP
// Remote debug over WiFi - not recommended for production, only for development
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
RemoteDebug Debug;
// SSID and password
const char* ssid = "........";
const char* password = "........";
// Time
uint32_t mLastTime = 0;
uint32_t mTimeSeconds = 0;
////// Setup
void setup() {
// Initialize the Serial (use only in setup codes)
Serial.begin(230400);
// Buildin led of ESP
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// Debug
Serial.println("**** Setup: initializing ...");
// WiFi connection
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Register host name in WiFi and mDNS
String hostNameWifi = HOST_NAME;
hostNameWifi.concat(".local");
#ifdef ESP8266 // Only for it
WiFi.hostname(hostNameWifi);
#endif
#ifdef USE_MDNS // Use the MDNS ?
if (MDNS.begin(HOST_NAME)) {
Serial.print("* MDNS responder started. Hostname -> ");
Serial.println(HOST_NAME);
}
MDNS.addService("telnet", "tcp", 23);
#endif
// Initialize RemoteDebug
Debug.begin(HOST_NAME); // Initialize the WiFi server
Debug.setResetCmdEnabled(true); // Enable the reset command
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
Debug.showColors(true); // Colors
// End off setup
Serial.println("* Arduino RemoteDebug Library");
Serial.println("*");
Serial.print("* WiFI connected. IP address: ");
Serial.println(WiFi.localIP());
Serial.println("*");
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
Serial.println("*");
Serial.println("* This sample will send messages of debug in all levels.");
Serial.println("*");
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
Serial.println("*");
}
void loop()
{
// Each second
if ((millis() - mLastTime) >= 1000) {
// Time
mLastTime = millis();
mTimeSeconds++;
// Blink the led
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
// Debug the time (verbose level)
debugV("* Time: %u seconds (VERBOSE)", mTimeSeconds);
if (mTimeSeconds % 5 == 0) { // Each 5 seconds
// Debug levels
debugV("* This is a message of debug level VERBOSE");
debugD("* This is a message of debug level DEBUG");
debugI("* This is a message of debug level INFO");
debugW("* This is a message of debug level WARNING");
debugE("* This is a message of debug level ERROR");
// Call a function
foo();
}
}
// RemoteDebug handle
Debug.handle();
// Give a time for ESP
yield();
}
// Function example to show a new auto function name of debug* macros
void foo() {
uint8_t var = 1;
debugV("this is a debug - var %u", var);
debugV("This is a println");
}
/////////// End

View File

@@ -1,893 +0,0 @@
////////
// Library: Remote debug - debug over WiFi - for Esp8266 (NodeMCU) or ESP32
// Author : Joao Lopes
// File : RemoteDebugger.ino
// Notes :
//
// Attention: This library is only for help development. Please not use this in production
//
// This example use the RemoteDebugger library: ao addon to Remotedebug with an simple software debug, based on SerialDebug library
// Attention: this library must be installed too
// Please open github repo to informations: //https://github.com/JoaoLopesF/RemoteDebugger
//
// Example of use:
//
//#ifndef DEBUG_DISABLED
// if (Debug.isActive(Debug.<level>)) { // <--- This is very important to reduce overheads and work of debug levels
// Debug.printf("bla bla bla: %d %s\n", number, str);
// Debug.println("bla bla bla");
// }
//#endif
//
// Or short way (prefered if only one debug at time)
//
// debugA("This is a any (always showed) - var %d", var);
//
// debugV("This is a verbose - var %d", var);
// debugD("This is a debug - var %d", var);
// debugI("This is a information - var %d", var);
// debugW("This is a warning - var %d", var);
// debugE("This is a error - var %d", var);
//
// debugV("This is println");
//
///////
////// Defines
// Host name (please change it)
#define HOST_NAME "remotedebug"
// Board especific libraries
#if defined ESP8266 || defined ESP32
// Use mDNS ? (comment this do disable it)
#define USE_MDNS true
// Arduino OTA (uncomment this to enable)
//#define USE_ARDUINO_OTA true
#else
// RemoteDebug library is now only to Espressif boards,
// as ESP32 and ESP82266,
// If need for another WiFi boards,
// please add an issue about this
// and we will see if it is possible made the port for your board.
// access: https://github.com/JoaoLopesF/RemoteDebug/issues
#error "The board must be ESP8266 or ESP32"
#endif // ESP
// Web server (uncomment this to need this)
//#define WEB_SERVER_ENABLED true
////// Includes
#if defined ESP8266
// Includes of ESP8266
#include <ESP8266WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include <ESP8266mDNS.h>
#endif
#ifdef WEB_SERVER_ENABLED
#include <ESP8266WebServer.h>
#endif
#elif defined ESP32
// Includes of ESP32
#include <WiFi.h>
#ifdef USE_MDNS
#include <DNSServer.h>
#include "ESPmDNS.h"
#endif
#ifdef WEB_SERVER_ENABLED
#include <WebServer.h>
#endif
#else
#error "Now RemoteDebug support only boards Espressif, as ESP8266 and ESP32"
#endif // ESP
// Arduino OTA
#ifdef USE_ARDUINO_OTA
#include <ArduinoOTA.h>
#endif
// HTTP Web server
#ifdef WEB_SERVER_ENABLED
#if defined ESP8266
ESP8266WebServer HTTPServer(80);
#elif defined ESP32
WebServer HTTPServer(80);
#endif
#endif // WEB_SERVER_ENABLED
// Remote debug over WiFi - not recommended for production/release, only for development
// Options for RemoteDebug of this project
// Attention: read this, before you change any option
//
// If yot changed it and not works, the compiler is using catching old compiled files
// To workaround this:
// - If have a clean project option (as Eclipse/Platformio), do it
// - or force compiler to compiler all (changing any configuration of board)
// - or to this change globally in RemoteDebugCfg.h (on library directory)
// - And upload again
//
// thanks to @22MarioZ for added this issue
// Disable all debug ?
// Important to compile for prodution/release
// Disable all debug ? Good to release builds (production)
// as nothing of RemoteDebug is compiled, zero overhead :-)
// Uncomment the line below, to do it:
//#define DEBUG_DISABLED true
// Disable te auto function feature of RemoteDebug
// Good if your code already have func name on debug messages
// Uncomment the line below, to do it:
//#define DEBUG_DISABLE_AUTO_FUNC true
// Disable Websocket? This is used with RemoteDebugApp connection
// Uncomment the line below, to do it:
//#define WEBSOCKET_DISABLED true
#ifndef WEBSOCKET_DISABLED // Only if Web socket enabled (RemoteDebugApp)
// If enabled, you can change the port here (8232 is default)
// Uncomment the line below, to do it:
//#define WEBSOCKET_PORT 8232
// Internally, the RemoteDebug uses a local copy of the arduinoWebSockets library (https://github.com/Links2004/arduinoWebSockets)
// Due it not in Arduino Library Manager
// If your project already use this library,
// Uncomment the line below, to do it:
//#define USE_LIB_WEBSOCKET true
#endif
#include "RemoteDebug.h" //https://github.com/JoaoLopesF/RemoteDebug
#ifndef DEBUG_DISABLED // Only if debug is not disabled (for production/release)
// RemoteDebug addon library: RemoteDebugger, an Simple software debugger - based on SerialDebug Library
#include "RemoteDebugger.h" //https://github.com/JoaoLopesF/RemoteDebugger
// Instance of RemoteDebug
RemoteDebug Debug;
#endif
// WiFi credentials
// Note: if commented, is used the smartConfig
// That allow to it in mobile app
// See more details in http://www.iotsharing.com/2017/05/how-to-use-smartconfig-on-esp32.html
//#define WIFI_SSID "..." // your network SSID (name)
//#define WIFI_PASS "..." // your network key
/////// Variables
// Time
uint32_t mTimeToSec = 0;
uint8_t mRunSeconds = 0;
uint8_t mRunMinutes = 0;
uint8_t mRunHours = 0;
// Globals for example of debugger
boolean mBoolean = false;
char mChar = 'X';
byte mByte = 'Y';
int mInt = 1;
unsigned int mUInt = 2;
long mLong = 3;
unsigned long mULong = 4;
float mFloat = 5.0f;
double mDouble = 6.0;
String mString = "This is a string";
String mStringLarge = "This is a large stringggggggggggggggggggggggggggggggggggggggggggggg";
char mCharArray[] = "This is a char array";
char mCharArrayLarge[] = "This is a large char arrayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
int mIntArray[5] = {1 ,2 ,3, 4, 5};
//const char mCharArrayConst[] = "This is const";
////// Setup
void setup() {
// Initialize the Serial (use only in setup codes)
Serial.begin(230400);
// Buildin led
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
#endif
// Connect WiFi
connectWiFi();
// Host name of WiFi
#ifdef ESP8266
WiFi.hostname(HOST_NAME);
#endif
#ifdef USE_ARDUINO_OTA
// Update over air (OTA)
initializeOTA();
#endif
// Register host name in mDNS
#if defined USE_MDNS && defined HOST_NAME
if (MDNS.begin(HOST_NAME)) {
Serial.print("* MDNS responder started. Hostname -> ");
Serial.println(HOST_NAME);
}
// Register the services
#ifdef WEB_SERVER_ENABLED
MDNS.addService("http", "tcp", 80); // Web server
#endif
#ifndef DEBUG_DISABLED
MDNS.addService("telnet", "tcp", 23);// Telnet server RemoteDebug
#endif
#endif // MDNS
// HTTP web server
#ifdef WEB_SERVER_ENABLED
HTTPServer.on("/", handleRoot);
HTTPServer.onNotFound(handleNotFound);
HTTPServer.begin();
Serial.println("* HTTP server started");
#endif
#ifndef DEBUG_DISABLED // Only for development
// Initialize RemoteDebug
Debug.begin(HOST_NAME); // Initialize the WiFi server
//Debug.setPassword("r3m0t0."); // Password on telnet connection ?
Debug.setResetCmdEnabled(true); // Enable the reset command
Debug.showProfiler(true); // Profiler (Good to measure times, to optimize codes)
Debug.showColors(true); // Colors
// Debug.setSerialEnabled(true); // if you wants serial echo - only recommended if ESP is plugged in USB
// Project commands
String helpCmd = "bench1 - Benchmark 1\n";
helpCmd.concat("bench2 - Benchmark 2");
Debug.setHelpProjectsCmds(helpCmd);
Debug.setCallBackProjectCmds(&processCmdRemoteDebug);
// Init the simple software debugger, based on SerialDebug library
#ifndef DEBUG_DISABLE_DEBUGGER
Debug.initDebugger(debugGetDebuggerEnabled, debugHandleDebugger, debugGetHelpDebugger, debugProcessCmdDebugger); // Set the callbacks
debugInitDebugger(&Debug); // Init the debugger
// Add Functions and global variables to RemoteDebuggger
// Notes: descriptions is optionals
// Add functions that can called from SerialDebug
if (debugAddFunctionVoid("benchInt", &benchInt) >= 0) {
debugSetLastFunctionDescription("To run a benchmark of integers");
}
if (debugAddFunctionVoid("benchFloat", &benchFloat) >= 0) {
debugSetLastFunctionDescription("To run a benchmark of float");
}
if (debugAddFunctionVoid("benchGpio", &benchGpio) >= 0) {
debugSetLastFunctionDescription("To run a benchmark of Gpio operations");
}
if (debugAddFunctionVoid("benchAll", &benchAll) >= 0) {
debugSetLastFunctionDescription("To run all benchmarks");
}
if (debugAddFunctionStr("funcArgStr", &funcArgStr) >= 0) {
debugSetLastFunctionDescription("To run with String arg");
}
if (debugAddFunctionChar("funcArgChar", &funcArgChar) >= 0) {
debugSetLastFunctionDescription("To run with Character arg");
}
if (debugAddFunctionInt("funcArgInt", &funcArgInt) >= 0) {
debugSetLastFunctionDescription("To run with Integer arg");
}
// Add global variables that can showed/changed from SerialDebug
// Note: Only global, if pass local for SerialDebug, can be dangerous
if (debugAddGlobalUInt8_t("mRunSeconds", &mRunSeconds) >= 0) {
debugSetLastGlobalDescription("Seconds of run time");
}
if (debugAddGlobalUInt8_t("mRunMinutes", &mRunMinutes) >= 0) {
debugSetLastGlobalDescription("Minutes of run time");
}
if (debugAddGlobalUInt8_t("mRunHours", &mRunHours) >= 0) {
debugSetLastGlobalDescription("Hours of run time");
}
// Note: easy way, no descriptions ....
debugAddGlobalBoolean("mBoolean", &mBoolean);
debugAddGlobalChar("mChar", &mChar);
debugAddGlobalByte("mByte", &mByte);
debugAddGlobalInt("mInt", &mInt);
debugAddGlobalUInt("mUInt", &mUInt);
debugAddGlobalLong("mLong", &mLong);
debugAddGlobalULong("mULong", &mULong);
debugAddGlobalFloat("mFloat", &mFloat);
debugAddGlobalDouble("mDouble", &mDouble);
debugAddGlobalString("mString", &mString);
// Note: For char arrays, not use the '&'
debugAddGlobalCharArray("mCharArray", mCharArray);
// Note, here inform to show only 20 characteres of this string or char array
debugAddGlobalString("mStringLarge", &mStringLarge, 20);
debugAddGlobalCharArray("mCharArrayLarge",
mCharArrayLarge, 20);
// For arrays, need add for each item (not use loop for it, due the name can not by a variable)
// Notes: Is good added arrays in last order, to help see another variables
// In next versions, we can have a helper to do it in one command
debugAddGlobalInt("mIntArray[0]", &mIntArray[0]);
debugAddGlobalInt("mIntArray[1]", &mIntArray[1]);
debugAddGlobalInt("mIntArray[2]", &mIntArray[2]);
debugAddGlobalInt("mIntArray[3]", &mIntArray[3]);
debugAddGlobalInt("mIntArray[4]", &mIntArray[4]);
// Add watches for some global variables
// Note: watches can be added/changed in serial monitor too
// Watch -> mBoolean when changed (put 0 on value)
debugAddWatchBoolean("mBoolean", DEBUG_WATCH_CHANGED, 0);
// Watch -> mRunSeconds == 10
debugAddWatchUInt8_t("mRunSeconds", DEBUG_WATCH_EQUAL, 10);
// Watch -> mRunMinutes > 3
debugAddWatchUInt8_t("mRunMinutes", DEBUG_WATCH_GREAT, 3);
// Watch -> mRunMinutes == mRunSeconds (just for test)
debugAddWatchCross("mRunMinutes", DEBUG_WATCH_EQUAL, "mRunSeconds");
#endif
// End of setup - show IP
Serial.println("* Arduino RemoteDebug Library");
Serial.println("*");
Serial.print("* WiFI connected. IP address: ");
Serial.println(WiFi.localIP());
Serial.println("*");
Serial.println("* Please use the telnet client (telnet for Mac/Unix or putty and others for Windows)");
Serial.println("* or the RemoteDebugApp (in browser: http://joaolopesf.net/remotedebugapp)");
Serial.println("*");
Serial.println("* This sample will send messages of debug in all levels.");
Serial.println("*");
Serial.println("* Please try change debug level in client (telnet or web app), to see how it works");
Serial.println("*");
#endif
}
void loop() {
#ifndef DEBUG_DISABLED
// Time of begin of this loop
uint32_t timeBeginLoop = millis();
#endif
// Each second
if (millis() >= mTimeToSec) {
// Time
mTimeToSec = millis() + 1000;
// Count run time (just a test - for real suggest the TimeLib and NTP, if board have WiFi)
mRunSeconds++;
if (mRunSeconds == 60) {
mRunMinutes++;
mRunSeconds = 0;
}
if (mRunMinutes == 60) {
mRunHours++;
mRunMinutes = 0;
}
if (mRunHours == 24) {
mRunHours = 0;
}
// Blink the led
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
#endif
// Debug the time (verbose level)
debugV("* Time: %u seconds (VERBOSE)", mRunSeconds);
if (mRunSeconds % 5 == 0) { // Each 5 seconds
// Debug levels
debugV("* This is a message of debug level VERBOSE");
debugD("* This is a message of debug level DEBUG");
debugI("* This is a message of debug level INFO");
debugW("* This is a message of debug level WARNING");
debugE("* This is a message of debug level ERROR");
// RemoteDebug isActive? Use this RemoteDebug sintaxe if you need process anything only for debug
// It is good to avoid overheads (this is only use that is suggest to use isActive)
// Note this need be surrounded by DEBUG_DISABLED precompiler condition to not compile for production/release
#ifndef DEBUG_DISABLED
if (Debug.isActive(Debug.VERBOSE)) {
Debug.println("Calling a foo function");
Debug.printf("At time of %d sec.\n", mRunSeconds);
// Call a function
foo();
}
#endif
}
}
////// Services on Wifi
#ifdef USE_ARDUINO_OTA
// Update over air (OTA)
ArduinoOTA.handle();
#endif
#ifdef WEB_SERVER_ENABLED
// Web server
HTTPServer.handleClient();
#endif
#ifndef DEBUG_DISABLED
// Remote debug over telnet
Debug.handle();
#endif
// Give a time for ESP
yield();
#ifndef DEBUG_DISABLED
// Show a debug - warning if time of these loop is over 50 (info) or 100 ms (warning)
uint32_t time = (millis() - timeBeginLoop);
if (time > 100) {
debugI("* Time elapsed for the loop: %u ms.", time);
} else if (time > 200) {
debugW("* Time elapsed for the loop: %u ms.", time);
}
#endif
}
// Function example to show a new auto function name of debug* macros
void foo() {
uint8_t var = 1;
debugV("this is a debug - var %u", var);
debugV("This is a println");
}
#ifndef DEBUG_DISABLED
// Process commands from RemoteDebug
void processCmdRemoteDebug() {
String lastCmd = Debug.getLastCommand();
if (lastCmd == "bench1") {
// Benchmark 1 - Printf
debugA("* Benchmark 1 - one Printf");
uint32_t timeBegin = millis();
uint8_t times = 50;
for (uint8_t i = 1; i <= times; i++) {
debugA("%u - 1234567890 - AAAA", i);
}
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
(millis() - timeBegin));
} else if (lastCmd == "bench2") {
// Benchmark 2 - Print/println
debugA("* Benchmark 2 - Print/Println");
uint32_t timeBegin = millis();
uint8_t times = 50;
for (uint8_t i = 1; i <= times; i++) {
if (Debug.isActive(Debug.ANY)) {
Debug.print(i);
Debug.print(" - 1234567890");
Debug.println(" - AAAA");
}
}
debugA("* Time elapsed for %u printf: %ld ms.\n", times,
(millis() - timeBegin));
}
}
#endif
////// Benchmarks - simple
// Note: how it as called by SerialDebug, must be return type void and no args
// Note: Flash F variables is not used during the tests, due it is slow to use in loops
#define BENCHMARK_EXECS 10000
// Simple benckmark of integers
void benchInt() {
int test = 0;
for (int i = 0; i < BENCHMARK_EXECS; i++) {
// Some integer operations
test++;
test += 2;
test -= 2;
test *= 2;
test /= 2;
}
// Note: Debug always is used here
debugA("*** Benchmark of integers. %u exec.", BENCHMARK_EXECS);
}
// Simple benckmark of floats
void benchFloat() {
float test = 0;
for (int i = 0; i < BENCHMARK_EXECS; i++) {
// Some float operations
test++;
test += 2;
test -= 2;
test *= 2;
test /= 2;
}
// Note: Debug always is used here
debugA("*** Benchmark of floats, %u exec.", BENCHMARK_EXECS);
}
// Simple benckmark of GPIO
void benchGpio() {
// const int execs = (BENCHMARK_EXECS / 10); // Reduce it
const int execs = BENCHMARK_EXECS;
for (int i = 0; i < execs; i++) {
// Some GPIO operations
digitalWrite(LED_BUILTIN, HIGH);
digitalRead(LED_BUILTIN);
digitalWrite(LED_BUILTIN, LOW);
analogRead(A0);
analogRead(A0);
analogRead(A0);
}
// Note: Debug always is used here
debugA("*** Benchmark of GPIO. %u exec.", execs);
}
// Run all benchmarks
void benchAll() {
benchInt();
benchFloat();
benchGpio();
// Note: Debug always is used here
debugA("*** All Benchmark done.");
}
// Example functions with argument (only 1) to call from serial monitor
// Note others types is not yet available in this version of SerialDebug
void funcArgStr (String str) {
debugA("*** called with arg.: %s", str.c_str());
}
void funcArgChar (char character) {
debugA("*** called with arg.: %c", character);
}
void funcArgInt (int number) {
debugA("*** called with arg.: %d", number);
}
////// WiFi
void connectWiFi() {
////// Connect WiFi
#ifdef EM_DEPURACAO
Serial.println("*** connectWiFi: begin conection ...");
#endif
#ifdef ESP32
// ESP32 // TODO: is really necessary ?
WiFi.enableSTA(true);
delay(100);
#endif
// Connect with SSID and password stored
#ifndef WIFI_SSID
WiFi.begin();
#else
WiFi.begin(WIFI_SSID, WIFI_PASS);
#endif
// Wait connection
uint32_t timeout = millis() + 20000; // Time out
while (WiFi.status() != WL_CONNECTED && millis() < timeout) {
delay(250);
Serial.print(".");
}
// Not connected yet?
if (WiFi.status() != WL_CONNECTED) {
#ifndef WIFI_SSID
// SmartConfig
WiFi.beginSmartConfig();
// Wait for SmartConfig packet from mobile
Serial.println("connectWiFi: Waiting for SmartConfig.");
while (!WiFi.smartConfigDone()) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("connectWiFi: SmartConfig received.");
// Wait for WiFi to connect to AP
Serial.println("connectWiFi: Waiting for WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
#else
Serial.println("Not possible connect to WiFi, rebooting");
ESP.restart();
#endif
}
// End
Serial.println("");
Serial.print("connectWiFi: connect a ");
Serial.println(WiFi.SSID());
Serial.print("IP: ");
Serial.println(WiFi.localIP().toString());
}
#ifdef USE_ARDUINO_OTA
// Initialize o Arduino OTA
void initializeOTA() {
// TODO: option to authentication (password)
#if defined ESP8266
ArduinoOTA.onStart([]() {
Serial.println("* OTA: Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\n*OTA: End");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("*OTA: Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("*OTA: Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
#elif defined ESP32
// ArduinoOTA
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
Serial.println("Start updating " + type);
}).onEnd([]() {
Serial.println("\nEnd");
}).onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
}).onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
#endif
// Begin
ArduinoOTA.begin();
}
#endif
#ifdef WEB_SERVER_ENABLED
/////////// Handles
void handleRoot() {
// Root web page
HTTPServer.send(200, "text/plain", "hello from esp - RemoteDebug Sample!");
}
void handleNotFound(){
// Page not Found
String message = "File Not Found\n\n";
message.concat("URI: ");
message.concat(HTTPServer.uri());
message.concat("\nMethod: ");
message.concat((HTTPServer.method() == HTTP_GET)?"GET":"POST");
message.concat("\nArguments: ");
message.concat(HTTPServer.args());
message.concat("\n");
for (uint8_t i=0; i<HTTPServer.args(); i++){
message.concat(" " + HTTPServer.argName(i) + ": " + HTTPServer.arg(i) + "\n");
}
HTTPServer.send(404, "text/plain", message);
}
#endif
/////////// End

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

View File

@@ -1,14 +0,0 @@
{
"name": "RemoteDebug",
"keywords": "Debug, Remote, Telnet, WiFi",
"description": "A library for Arduino to debug projects over WiFi, with web app or telnet client, with Print commands like Serial Monitor.",
"repository":
{
"type": "git",
"url": "https://github.com/JoaoLopesF/RemoteDebug.git"
},
"version": "3.0.5",
"frameworks": "arduino",
"platforms": "*"
}

View File

@@ -1,9 +0,0 @@
name=RemoteDebug
version=3.0.5
author=Joao Lopes
maintainer=Joao Lopes
sentence=A library for Arduino to debug projects over WiFi, with web app or telnet client, with Print commands like Serial Monitor.
paragraph=
category=Communication
url=https://github.com/JoaoLopesF/RemoteDebug
architectures=*

File diff suppressed because it is too large Load Diff

View File

@@ -1,459 +0,0 @@
/*
* Header for RemoteDebug
*
* MIT License
*
* Copyright (c) 2019 Joao Lopes
*
* 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.
*
*
*/
#ifndef REMOTEDEBUG_H
#define REMOTEDEBUG_H
#pragma once
///// RemoteDebug configuration
#include "RemoteDebugCfg.h"
// Debug enabled ?
#ifndef DEBUG_DISABLED
//////// Defines
// New color system (comment this to return to old system) - 2019-02-27
#define COLOR_NEW_SYSTEM true
// ANSI Colors
#define COLOR_RESET "\x1B[0m"
#define COLOR_BLACK "\x1B[0;30m"
#define COLOR_RED "\x1B[0;31m"
#define COLOR_GREEN "\x1B[0;32m"
#define COLOR_YELLOW "\x1B[0;33m"
#define COLOR_BLUE "\x1B[0;34m"
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
#define COLOR_DARK_BLACK "\x1B[1;30m"
#define COLOR_LIGHT_RED "\x1B[1;31m"
#define COLOR_LIGHT_GREEN "\x1B[1;32m"
#define COLOR_LIGHT_YELLOW "\x1B[1;33m"
#define COLOR_LIGHT_BLUE "\x1B[1;34m"
#define COLOR_LIGHT_MAGENTA "\x1B[1;35m"
#define COLOR_LIGHT_CYAN "\x1B[1;36m"
#define COLOR_LIGHT_WHITE "\x1B[1;37m"
#define COLOR_BACKGROUND_BLACK "\x1B[40m"
#define COLOR_BACKGROUND_RED "\x1B[41m"
#define COLOR_BACKGROUND_GREEN "\x1B[42m"
#define COLOR_BACKGROUND_YELLOW "\x1B[43m"
#define COLOR_BACKGROUND_BLUE "\x1B[44m"
#define COLOR_BACKGROUND_MAGENTA "\x1B[45m"
#define COLOR_BACKGROUND_CYAN "\x1B[46m"
#define COLOR_BACKGROUND_WHITE "\x1B[47m"
#ifdef COLOR_NEW_SYSTEM
// New system of Colors
// Note: this colors is not equals to SerialDebug colors, due using standard 16 colors of Ansi, for compatibility
#define COLOR_VERBOSE COLOR_GREEN
#define COLOR_DEBUG COLOR_LIGHT_GREEN
//#define COLOR_INFO COLOR_YELLOW
//#define COLOR_WARNING COLOR_CYAN
//#define COLOR_ERROR COLOR_RED
#define COLOR_INFO COLOR_LIGHT_YELLOW
#define COLOR_WARNING COLOR_LIGHT_CYAN
#define COLOR_ERROR COLOR_LIGHT_RED
#define COLOR_RAW COLOR_WHITE // COLOR_MAGENTA
#endif
//////// Includes
#include "Arduino.h"
#include "Print.h"
// ESP8266 or ESP32 ?
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#else
#error "Only for ESP8266 or ESP32"
#endif
////// Shortcuts macros
// Auto function for debug macros?
#ifndef DEBUG_DISABLE_AUTO_FUNC // With auto func
#ifdef ESP32
// ESP32 -> Multicore - show core id ?
#define DEBUG_AUTO_CORE true // debug show core id ? (comment to disable it)
#ifdef DEBUG_AUTO_CORE
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s)(C%d) " fmt, __func__, xPortGetCoreID(), ##__VA_ARGS__)
#endif
#endif
#ifndef DEBUG_AUTO_CORE // No auto core or for ESP8266
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf("(%s) " fmt, __func__, ##__VA_ARGS__)
#endif
#else // Without auto func
#define rdebugA(fmt, ...) if (Debug.isActive(Debug.ANY)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugP(fmt, ...) if (Debug.isActive(Debug.PROFILER)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugV(fmt, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugD(fmt, ...) if (Debug.isActive(Debug.DEBUG)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugI(fmt, ...) if (Debug.isActive(Debug.INFO)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugW(fmt, ...) if (Debug.isActive(Debug.WARNING)) Debug.printf(fmt, ##__VA_ARGS__)
#define rdebugE(fmt, ...) if (Debug.isActive(Debug.ERROR)) Debug.printf(fmt, ##__VA_ARGS__)
#endif
// With newline
#define rdebugAln(fmt, ...) rdebugA(fmt "\n", ##__VA_ARGS__)
#define rdebugPln(fmt, ...) rdebugP(fmt "\n", ##__VA_ARGS__)
#define rdebugVln(fmt, ...) rdebugV(fmt "\n", ##__VA_ARGS__)
#define rdebugDln(fmt, ...) rdebugD(fmt "\n", ##__VA_ARGS__)
#define rdebugIln(fmt, ...) rdebugI(fmt "\n", ##__VA_ARGS__)
#define rdebugWln(fmt, ...) rdebugW(fmt "\n", ##__VA_ARGS__)
#define rdebugEln(fmt, ...) rdebugE(fmt "\n", ##__VA_ARGS__)
// For old versions compatibility
#define rdebug(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
// Another way - for compatibility
#define DEBUG(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
#define DEBUG_A(fmt, ...) rdebugA(fmt, ##__VA_ARGS__)
#define DEBUG_P(fmt, ...) rdebugP(fmt, ##__VA_ARGS__)
#define DEBUG_V(fmt, ...) rdebugV(fmt, ##__VA_ARGS__)
#define DEBUG_D(fmt, ...) rdebugD(fmt, ##__VA_ARGS__)
#define DEBUG_I(fmt, ...) rdebugI(fmt, ##__VA_ARGS__)
#define DEBUG_W(fmt, ...) rdebugW(fmt, ##__VA_ARGS__)
#define DEBUG_E(fmt, ...) rdebugE(fmt, ##__VA_ARGS__)
// New way: To compatibility with SerialDebug (can use RemoteDebug or SerialDebug)
// This is my favorite :)
#define debugV(fmt, ...) rdebugVln(fmt, ##__VA_ARGS__)
#define debugD(fmt, ...) rdebugDln(fmt, ##__VA_ARGS__)
#define debugI(fmt, ...) rdebugIln(fmt, ##__VA_ARGS__)
#define debugW(fmt, ...) rdebugWln(fmt, ##__VA_ARGS__)
#define debugE(fmt, ...) rdebugEln(fmt, ##__VA_ARGS__)
#define debugA(fmt, ...) rdebugAln(fmt, ##__VA_ARGS__)
#define debugHandle() Debug.handle()
// Macros used by code converter for codes with several prints to only message
// due the converter cannot
// convert severals Serial.print in one debug* macro.
#define rprintV(x, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.print(x, ##__VA_ARGS__)
#define rprintD(x, ...) if (Debug.isActive(Debug.DEBUG)) Debug.print(x, ##__VA_ARGS__)
#define rprintI(x, ...) if (Debug.isActive(Debug.INFO)) Debug.print(x, ##__VA_ARGS__)
#define rprintW(x, ...) if (Debug.isActive(Debug.WARNING)) Debug.print(x, ##__VA_ARGS__)
#define rprintE(x, ...) if (Debug.isActive(Debug.ERROR)) Debug.print(x, ##__VA_ARGS__)
#define rprintA(x, ...) if (Debug.isActive(Debug.ANY)) Debug.print(x, ##__VA_ARGS__)
#define rprintVln(x, ...) if (Debug.isActive(Debug.VERBOSE)) Debug.println(x, ##__VA_ARGS__)
#define rprintDln(x, ...) if (Debug.isActive(Debug.DEBUG)) Debug.println(x, ##__VA_ARGS__)
#define rprintIln(x, ...) if (Debug.isActive(Debug.INFO)) Debug.println(x, ##__VA_ARGS__)
#define rprintWln(x, ...) if (Debug.isActive(Debug.WARNING)) Debug.println(x, ##__VA_ARGS__)
#define rprintEln(x, ...) if (Debug.isActive(Debug.ERROR)) Debug.println(x, ##__VA_ARGS__)
#define rprintAln(x, ...) if (Debug.isActive(Debug.ANY)) Debug.println(x, ##__VA_ARGS__)
///// Class
class RemoteDebug: public Print
{
public:
// Constructor
RemoteDebug();
// Methods
bool begin(String hostName, uint16_t port, uint8_t startingDebugLevel = DEBUG);
bool begin(String hostName, uint8_t startingDebugLevel = DEBUG);
void setPassword(String password);
void stop();
void handle();
void disconnect(boolean onlyTelnetClient = false);
void setSerialEnabled(boolean enable);
void setResetCmdEnabled(boolean enable);
void setHelpProjectsCmds(String help);
void setCallBackProjectCmds(void (*callback)());
String getLastCommand();
void clearLastCommand();
void showTime(boolean show);
void showProfiler(boolean show, uint32_t minTime = 0);
void showDebugLevel(boolean show);
void showColors(boolean show);
void showRaw(boolean show);
void setCallBackNewClient(void (*callback)());
#ifdef ALPHA_VERSION // In test, not good yet
void autoProfilerLevel(uint32_t millisElapsed);
#endif
void setFilter(String filter);
void setNoFilter();
boolean isActive(uint8_t debugLevel = DEBUG);
void silence(boolean activate, boolean showMessage = true, boolean fromBreak = false, uint32_t timeout = 0);
boolean isSilence();
void onConnection(boolean connected);
boolean isConnected();
#ifdef DEBUGGER_ENABLED
// For Simple software debugger - based on SerialDebug Library
void initDebugger(boolean (*callbackEnabled)(), void (*callbackHandle)(const boolean), String (*callbackGetHelp)(), void (*callbackProcessCmd)());
WiFiClient* getTelnetClient();
#endif
#ifndef WEBSOCKET_DISABLED // For web socket server (app)
void wsOnReceive(const char* command);
void wsSendInfo();
void wsSendLevelInfo();
#endif
boolean wsIsConnected();
// Print
virtual size_t write(uint8_t);
virtual size_t write(const uint8_t *buffer, size_t size); // Insert due a write bug w/ latest Esp8266 SDK - 17/08/18
// Debug levels
static const uint8_t PROFILER = 0; // Used for show time of execution of pieces of code(profiler)
static const uint8_t VERBOSE = 1; // Used for show verboses messages
static const uint8_t DEBUG = 2; // Used for show debug messages
static const uint8_t INFO = 3; // Used for show info messages
static const uint8_t WARNING = 4; // Used for show warning messages
static const uint8_t ERROR = 5; // Used for show error messages
static const uint8_t ANY = 6; // Used for show always messages, for any current debug level
// Expand characters as CR/LF to \\r, \\n
String expand(String string);
// Destructor
~RemoteDebug();
private:
// Variables
String _hostName = ""; // Host name
boolean _connected = false; // Client is connected ?
String _password = ""; // Password
boolean _passwordOk = false; // Password request ? - 18/07/18
uint8_t _passwordAttempt = 0;
boolean _silence = false; // Silence mode ?
uint32_t _silenceTimeout = 0; // Silence timeout
uint8_t _clientDebugLevel = DEBUG; // Level setted by user in web app or telnet client
uint8_t _lastDebugLevel = DEBUG; // Last Level setted by active()
uint32_t _lastTimePrint = millis(); // Last time print a line
uint8_t _levelBeforeProfiler=DEBUG; // Last Level before Profiler level
uint32_t _levelProfilerDisable = 0; // time in millis to disable the profiler level
uint32_t _autoLevelProfiler = 0; // Automatic change to profiler level if time between handles is greater than n millis
boolean _showTime = false; // Show time in millis
boolean _showProfiler = false; // Show time between messages
uint32_t _minTimeShowProfiler = 0; // Minimal time to show profiler
boolean _showDebugLevel = true; // Show debug Level
boolean _showColors = false; // Show colors
boolean _showRaw = false; // Show in raw mode ?
boolean _serialEnabled = false; // Send to serial too (not recommended)
boolean _resetCommandEnabled=false; // Enable command to reset the board
boolean _newLine = true; // New line write ?
String _command = ""; // Command received
String _lastCommand = ""; // Last Command received
uint32_t _lastTimeCommand = millis();// Last time command received
String _helpProjectCmds = ""; // Help of comands setted by project (sketch)
void (*_callbackProjectCmds)() = NULL; // Callable for projects commands
void (*_callbackNewClient)() = NULL; // Callable for when have a new client connected
String _filter = ""; // Filter
boolean _filterActive = false;
String _bufferPrint = ""; // Buffer of print write to WiFi
#ifdef CLIENT_BUFFERING
String _bufferSend = ""; // Buffer to send data to web app or telnet client
uint16_t _sizeBufferSend = 0; // Size of it
uint32_t _lastTimeSend = 0; // Last time command send data
#endif
#ifdef DEBUGGER_ENABLED
// // For Simple software debugger - based on SerialDebug Library
boolean (*_callbackDbgEnabled)() = NULL;// Callable for debugger enabled
void (*_callbackDbgHandle)(const boolean) = NULL; // Callable for handle of debugger
String (*_callbackDbgHelp)() = NULL; // Callable for get debugger help
void (*_callbackDbgProcessCmd)() = NULL;// Callable for process commands of debugger
#endif
//////// Privates
void showHelp();
void processCommand();
String formatNumber(uint32_t value, uint8_t size, char insert='0');
boolean isCRLF(char character);
uint32_t getFreeMemory();
#ifdef ALPHA_VERSION // In test, not good yet
void sendTelnetCommand(uint8_t command, uint8_t option);
#endif
};
#else // DEBUG_DISABLED
// Disable debug macros
#define rdebugAln(...)
#define rdebugPln(...)
#define rdebugVln(...)
#define rdebugDln(...)
#define rdebugIln(...)
#define rdebugWln(...)
#define rdebugEln(...)
#define rdebug(...)
#define DEBUG(...)
#define DEBUG_A(...)
#define DEBUG_P(...)
#define DEBUG_V(...)
#define DEBUG_D(...)
#define DEBUG_I(...)
#define DEBUG_W(...)
#define DEBUG_E(...)
#define debugA(...)
#define debugP(...)
#define debugV(...)
#define debugD(...)
#define debugI(...)
#define debugW(...)
#define debugE(...)
#define rprintA(...)
#define rprintV(...)
#define rprintD(...)
#define rprintI(...)
#define rprintW(...)
#define rprintE(...)
#define rprintAln(...)
#define rprintVln(...)
#define rprintDln(...)
#define rprintIln(...)
#define rprintWln(...)
#define rprintEln(...)
#define debugHandle()
// Note all of Debug. codes need uses "#ifndef DEBUG_DISABLED"
// For example, the initialization codes and:
//#ifndef DEBUG_DISABLED
//if (Debug.isActive(Debug.VERBOSE)) {
// Debug.printf("bla bla bla: %d %s", number, str); // OR
// Debug.printf("bla bla bla: %d %s", number, str.c_str()); // Note: if type is String need c_str() // OR
// Debug.println("bla bla bla 2 ln");
//}
//#endif
#endif // DEBUG_DISABLED
#endif // H
//////// End

View File

@@ -1,135 +0,0 @@
/*
* Header for RemoteDebugCfg
*
* MIT License
*
* Copyright (c) 2019 Joao Lopes
*
* 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.
*
*
*/
/*
* All configurations have moved to RemoteDebugCfg.h,
* to facilitate changes
*/
///////////// User config, to not lost in library updates
#ifndef REMOTEDEBUGCFG_H_
#define REMOTEDEBUGCFG_H_
#pragma once
///////////// For RemoteDebug ///////////////////
///// Debug disable for compile to production/release
///// as nothing of RemotedDebug is compiled, zero overhead :-)
//#define DEBUG_DISABLED true
// Debug enabled ?
#ifndef DEBUG_DISABLED
///// Port for telnet server
#define TELNET_PORT 23
// Disable auto function for debug macros? (uncomment this if not want this)
//#define DEBUG_DISABLE_AUTO_FUNC true
// Simple password request - left commented if not need this - 18/07/18
// Notes:
// It is very simple feature, only text, no cryptography,
// and the password is echoed in screen (I not discovery yet how disable it)
// telnet use advanced authentication (kerberos, etc.)
// Such now as RemoteDebug now is not for production releases,
// this kind of authentication will not be done now.
// Can be by project, just call setPassword method
#define REMOTEDEBUG_PWD_ATTEMPTS 3
// Maximum time for inactivity (em milliseconds)
// Default: 10 minutes
// Comment it if you not want this
// Can be by project, just define it before include this file
//#define MAX_TIME_INACTIVE 600000
// Buffered print write to WiFi -> length of buffer
// Can be by project, just define it before include this file
#define BUFFER_PRINT 170
// Should the help text be displayed on connection.
// Enabled by default, comment to disable
#define SHOW_HELP true
// Buffering (sends in interval of time to avoid ESP misterious delays)
// Uncomment this to disable it
#define CLIENT_BUFFERING true
#ifdef CLIENT_BUFFERING
#define DELAY_TO_SEND 10 // Time to send buffer
#define MAX_SIZE_SEND 1460 // Maximum size of packet (limit of TCP/IP)
#endif
// Enable if you test features yet in development
//#define ALPHA_VERSION true
// Debugger support enabled ?
// Comment this to disable it
#define DEBUGGER_ENABLED true
#ifdef DEBUGGER_ENABLED
#define DEBUGGER_HANDLE_TIME 850 // Interval to call handle of debugger - equal to implemented in debugger
// App have debugger elements on screen ?
// Note: app not have it yet
//#define DEBUGGER_SEND_INFO true
#endif
///// Websocket server to support debug over web browser (RemoteDebugApp)
// Uncomment this to disable it
#define WEBSOCKET_DISABLED true
///////////// For RemoteDebugWS ///////////////////
#ifndef WEBSOCKET_DISABLED
// Websocket port
#define WEBSOCKET_PORT 8232
// Library arduinoWebSockets already installed, uncomment to use it
// Do this if you receive errors of multiple definition ...
//#define USE_LIB_WEBSOCKET true
#endif
///////////// For RemoteDebugger ///////////////////
// Enable Flash variables support - F()
// Used internally in SerialDebug and in public API
// If is a low memory board, like AVR, all strings in SerialDebug is using flash memory
// If have RAM memory, this is more fast than flash
//#define DEBUG_USE_FLASH_F true
// For Espressif boards, default is not flash support for printf,
// due it have a lot of memory and Serial.printf is not compatible with it
// If you need more memory, can force it:
//#define DEBUG_USE_FLASH_F true
#endif /* DEBUG_DISABLED */
#endif /* REMOTEDEBUGCFG_H_ */
////// End

View File

@@ -1,88 +0,0 @@
/*
* telnet.h - Telnet Defines
*
* Note: only used is uncommented
* */
#ifndef TELNET_H
#define TELNET_TELNET_H
#define TELNET_IAC 255
#define TELNET_DONT 254
#define TELNET_DO 253
#define TELNET_WONT 252
#define TELNET_WILL 251
// #define TELNET_SE 240 // Subnegotiation End
// #define TELNET_NOP 241 // No Operation
// #define TELNET_DM 242 // Data Mark
// #define TELNET_BRK 243 // Break
// #define TELNET_IP 244 // Interrupt process
// #define TELNET_AO 245 // Abort output
// #define TELNET_AYT 246 // Are You There
// #define TELNET_EC 247 // Erase Character
// #define TELNET_EL 248 // Erase Line
//#define TELNET_GA 249 // Go Ahead
// #define TELNET_SB 250 // Subnegotiation Begin
// #define TELNET_BINARY 0 // 8-bit data path
#define TELNET_ECHO 1 // echo
// #define TELNET_RCP 2 // prepare to reconnect
#define TELNET_SGA 3 // suppress go ahead
// #define TELNET_NAMS 4 // approximate message size
// #define TELNET_STATUS 5 // give status
// #define TELNET_TM 6 // timing mark
// #define TELNET_RCTE 7 // remote controlled transmission and echo
// #define TELNET_NAOL 8 // negotiate about output line width
// #define TELNET_NAOP 9 // negotiate about output page size
// #define TELNET_NAOCRD 10 // negotiate about CR disposition
// #define TELNET_NAOHTS 11 // negotiate about horizontal tabstops
// #define TELNET_NAOHTD 12 // negotiate about horizontal tab disposition
// #define TELNET_NAOFFD 13 // negotiate about formfeed disposition
// #define TELNET_NAOVTS 14 // negotiate about vertical tab stops
// #define TELNET_NAOVTD 15 // negotiate about vertical tab disposition
// #define TELNET_NAOLFD 16 // negotiate about output LF disposition
// #define TELNET_XASCII 17 // extended ascii character set
// #define TELNET_LOGOUT 18 // force logout
// #define TELNET_BM 19 // byte macro
// #define TELNET_DET 20 // data entry terminal
// #define TELNET_SUPDUP 21 // supdup protocol
// #define TELNET_SUPDUPOUTPUT 22 // supdup output
// #define TELNET_SNDLOC 23 // send location
// #define TELNET_TTYPE 24 // terminal type
// #define TELNET_EOR 25 // end or record
// #define TELNET_TUID 26 // TACACS user identification
// #define TELNET_OUTMRK 27 // output marking
// #define TELNET_TTYLOC 28 // terminal location number
// #define TELNET_VT3270REGIME 29 // 3270 regime
// #define TELNET_X3PAD 30 // X.3 PAD
// #define TELNET_NAWS 31 // window size
// #define TELNET_TSPEED 32 // terminal speed
// #define TELNET_LFLOW 33 // remote flow control
// #define TELNET_LINEMODE 34 // Linemode option
// #define TELNET_XDISPLOC 35 // X Display Location
// #define TELNET_OLD_ENVIRON 36 // Old - Environment variables
// #define TELNET_AUTHENTICATION 37 // Authenticate
// #define TELNET_ENCRYPT 38 // Encryption option
// #define TELNET_NEW_ENVIRON 39 // New - Environment variables
// #define TELNET_TN3270E 40 // TN3270E
// #define TELNET_XAUTH 41 // XAUTH
// #define TELNET_CHARSET 42 // CHARSET
// #define TELNET_RSP 43 // Telnet Remote Serial Port
// #define TELNET_COM_PORT_OPTION 44 // Com Port Control Option
#define TELNET_SUPPRESS_LOCAL_ECHO 45 // Telnet Suppress Local Echo
// #define TELNET_TLS 46 // Telnet Start TLS
// #define TELNET_KERMIT 47 // KERMIT
// #define TELNET_SEND_URL 48 // SEND-URL
// #define TELNET_FORWARD_X 49 // FORWARD_X
// #define TELNET_PRAGMA_LOGON 138 // TELOPT PRAGMA LOGON
// #define TELNET_SSPI_LOGON 139 // TELOPT SSPI LOGON
// #define TELNET_PRAGMA_HEARTBEAT 140 // TELOPT PRAGMA HEARTBEAT
// #define TELNET_EXOPL 255 // Extended-Options-List
// #define TELNET_NOOPT 0
// #define TELNET_IS 0
// #define TELNET_SEND 1
#endif // TELNET_H

View File

@@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <http://unlicense.org>

View File

@@ -1,518 +0,0 @@
[![PlatformIO](https://github.com/chrisjoyce911/esp32FOTA/workflows/PlatformIO/badge.svg)](https://github.com/chrisjoyce911/esp32FOTA/actions/)
[![arduino-library-badge](https://www.ardu-badge.com/badge/esp32FOTA.svg?)](https://www.ardu-badge.com/esp32FOTA)
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/chrisjoyce911/library/esp32FOTA.svg)](https://registry.platformio.org/libraries/chrisjoyce911/esp32FOTA)
# esp32FOTA library for Arduino
## Purpose
A simple library to add support for Over-The-Air (OTA) updates to your project.
## Features
- [x] Zlib or gzip compressed firmware support
- [x] SPIFFS/LittleFS partition Update [#25], [#47], [#60], [#92] (thanks to all participants)
- [x] Any fs::FS support (SPIFFS/LITTLEFS/SD) for cert/signature storage [#79], [#74], [#91], [#92] (thanks to all participants)
- [x] Seamless http/https
- [x] Web update (requires web server)
- [x] Batch firmware sync
- [x] Force firmware update [#8]
- [x] https support [#26] ( Thanks to @fbambusi )
- [x] Signature check of downloaded firmware-image [#65]
- [x] Signature verification
- [x] Semantic versioning support
- [ ] Checking for update via bin headers [#15]
## How it works
This library tries to access a JSON file hosted on a webserver, and reviews it to decide if a newer firmware has been published, if so it will download it and install it.
There are a few things that need to be in place for an update to work.
- A webserver with the firmware information in a JSON file
- Firmware version
- Firmware type
- Firmware bin (can optionnally be compressed with zlib or gzip)
- For https or signature check: SPIFFS with root_ca.pem (https) and rsa_key.pem (signature check)
You can supply http or https URLs. If you are using https, you need the root_ca.pem in your SPIFFS partition. For the actual firmware it will use https when you define port 443 or 4433. Otherwise it will use plain http.
## Usage
### Hosted JSON
This is hosted by a webserver and contains information about the latest firmware:
```json
{
"type": "esp32-fota-http",
"version": 2,
"host": "192.168.0.100",
"port": 80,
"bin": "/fota/esp32-fota-http-2.bin"
}
```
Version information can be either a single number or a semantic version string. Alternatively, a full URL path can be provided:
```json
{
"type": "esp32-fota-http",
"version": "2.5.1",
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin"
}
```
A single JSON file can provide information on multiple firmware types by combining them together into an array. When this is loaded, the firmware manifest with a type matching the one passed to the esp32FOTA constructor will be selected:
```json
[
{
"type":"esp32-fota-http",
"version":"0.0.2",
"url":"http://192.168.0.100/fota/esp32-fota-http-2.bin"
},
{
"type":"esp32-other-hardware",
"version":"0.0.3",
"url":"http://192.168.0.100/fota/esp32-other-hardware.bin"
}
]
```
A single JSON file can also contain several versions of a single firmware type:
```json
[
{
"type":"esp32-fota-http",
"version":"0.0.2",
"url":"http://192.168.0.100/fota/esp32-fota-0.0.2.bin"
},
{
"type":"esp32-fota-http",
"version":"0.0.3",
"url":"http://192.168.0.100/fota/esp32-fota-0.0.3.bin",
"spiffs":"http://192.168.0.100/fota/esp32-fota-0.0.3.spiffs.bin"
}
]
```
#### Filesystem image (spiffs/littlefs)
Adding `spiffs` key to the JSON entry will end up with the filesystem being updated first, then the firmware.
Obviously don't use the filesystem you're updating to store certificates needed by the update, spiffs partition
doesn't have redundancy like OTA0/OTA1 and won't recover from a failed update without a restart and format.
```json
{
"type": "esp32-fota-http",
"version": 2,
"host": "192.168.0.100",
"port": 80,
"bin": "/fota/esp32-fota-http-2.bin",
"spiffs": "/fota/default_spiffs.bin"
}
```
Other accepted keys for filesystems are `spiffs`, `littlefs` and `fatfs`.
Picking one or another doesn't make any difference yet.
#### Firmware types
Types are used to compare with the current loaded firmware, this is used to make sure that when loaded, the device will still do the intended job.
As an example, a device used as a data logger should ony be updated with new versions of the data logger.
##### examples
- TTGO-T8-ESP32-Logger
- TTGO-T8-ESP32-Temp
- TTGO-T8-ESP32-Relay
### Debug
Messages depends of build level. If you pass -D CORE_DEBUG_LEVEL=3 to build flags, it enable the messages
### Sketch
In this early init example, a version 1 of 'esp32-fota-http' is in use, it would be updated when using the JSON example.
```cpp
#include <esp32FOTA.hpp>
const char *ssid = "";
const char *password = "";
esp32FOTA esp32FOTA("esp32-fota-http", "1.0.0");
const char* manifest_url = "http://server/fota/fota.json";
void setup()
{
Serial.begin(115200);
setup_wifi();
esp32FOTA.setManifestURL( manifest_url );
// esp32FOTA.useDeviceId( true ); // optionally append the device ID to the HTTP query
}
void setup_wifi()
{
delay(10);
Serial.print("Connecting to ");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
}
void loop()
{
esp32FOTA.handle();
// or ...
// bool updatedNeeded = esp32FOTA.execHTTPcheck();
// if (updatedNeeded) {
// esp32FOTA.execOTA();
// }
delay(2000);
}
```
Late init is possible using `FOTAConfig_t`, allowing more complex configurations:
```cpp
#include <SPIFFS.h> // include filesystem *before* esp32FOTA librart
#include <esp32FOTA.hpp>
esp32FOTA FOTA;
const char* manifest_url = "http://server/fota/fota.json";
const char* fota_name = "esp32-fota-http";
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SD );
void setup()
{
Serial.begin( 115200 );
setup_wifi();
{
auto cfg = FOTA.getConfig();
cfg.name = fota_name;
cfg.manifest_url = manifest_url;
cfg.sem = SemverClass( 1, 0, 0 ); // major, minor, patch
cfg.check_sig = false; // verify signed firmware with rsa public key
cfg.unsafe = true; // disable certificate check when using TLS
//cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
//cfg.use_device_id = false;
FOTA.setConfig( cfg );
}
}
void loop()
{
esp32FOTA.handle();
// or ...
// bool updatedNeeded = esp32FOTA.execHTTPcheck();
// if (updatedNeeded) {
// esp32FOTA.execOTA();
// }
delay(2000);
}
```
### Zlib/gzip support
⚠️ This feature cannot be used with signature check.
For firmwares compressed with `pigz` utility (see , file extension must be `.zz`:
```cpp
#include <flashz.hpp> // http://github.com/vortigont/esp32-flashz
#include <esp32FOTA.hpp>
```
```bash
$ pigz -9kzc esp32-fota-http-2.bin > esp32-fota-http-2.bin.zz
```
```json
{
"type": "esp32-fota-http",
"version": "2.5.1",
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin.zz"
}
```
For firmwares compressed with `gzip` utility, file extension must be `.gz`
```cpp
#include <ESP32-targz.h> // http://github.com/tobozo/ESP32-targz
#include <esp32FOTA.hpp>
```
```bash
$ gzip -c esp32-fota-http-2.bin > esp32-fota-http-2.bin.gz
```
```json
{
"type": "esp32-fota-http",
"version": "2.5.1",
"url": "http://192.168.0.100/fota/esp32-fota-http-2.bin.gz"
}
```
### Root Certificates
Certificates and signatures can be stored in different places: any fs::FS filesystem or progmem as const char*.
Filesystems:
```C++
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
```
```C++
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
```
```C++
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SD );
```
Progmem:
```C++
const char* root_ca = R"ROOT_CA(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)ROOT_CA";
// mixed sources is possible
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Root CA", root_ca, strlen(root_ca)+1 );
CryptoFileAsset *MyPubKey = new CryptoFileAsset("RSA Key", "/rsa_key.pub", &SD);
```
Then later in the `setup()`:
```C++
const char* manifest_url = "http://server/fota/fota.json";
void setup()
{
// (...)
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.setRootCA( MyRootCA );
esp32FOTA.setPubKey( MyPubKey );
}
```
# Update callbacks
## Progress callback
Can be used to draw a progress bar e.g. on a TFT.
The callback signature is: `void my_progress_callback( size_t progress, size_t size);`, lambda functions are accepted.
Use `esp32FOTA.setProgressCb( my_progress_callback )` to attach the callback.
This method is aliased to Update.h `onProgress()` feature and defaults to printing dots in the serial console.
```C++
void my_progress_callback( size_t progress, size_t size )
{
if( progress == size || progress == 0 ) Serial.println();
Serial.print(".");
}
void setup()
{
// (...)
// usage with callback function:
esp32FOTA.setProgressCb( my_progress_callback ) ;
// usage with lambda function:
esp32FOTA.setProgressCb( [](size_t progress, size_t size) {
if( progress == size || progress == 0 ) Serial.println();
Serial.print(".");
});
}
```
## Update begin-fail callback
- Description: fired when Update.begin() failed
- Callback type: `void(int partition)`
- Callback setter: `setUpdateBeginFailCb( cb )`
- Usage:
```cpp
esp32FOTA.setUpdateBeginFailCb( [](int partition) {
Serial.printf("Update could not begin with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
});
```
## Update end callback
- Description: fired after Update.end() and before signature check
- Callback type: `void(int partition)`
- Callback setter: `setUpdateEndCb( cb )`
- Usage:
```cpp
esp32FOTA.setUpdateEndCb( [](int partition) {
Serial.printf("Update could not finish with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
});
```
## Update check-fail callback
- Description: fired when partition or signature check failed
- Callback type: `void(int partition, int update_error_code)`
- Callback setter: `setUpdateCheckFailCb( cb )`
- Usage:
```cpp
esp32FOTA.setUpdateCheckFailCb( [](int partition, int error_code) {
Serial.printf("Update could validate %s partition (error %d)\n", partition==U_SPIFFS ? "spiffs" : "firmware", error_code );
// error codes:
// -1 : partition not found
// -2 : validation (signature check) failed
});
```
## Update finished callback
- Description: fired update is complete
- Callback type: `void(int partition, bool needs_restart)`
- Callback setter: `setUpdateFinishedCb( cb )`
- Usage:
```cpp
esp32FOTA.setUpdateFinishedCb( [](int partition, bool restart_after) {
Serial.printf("Update could not begin with %s partition\n", partition==U_SPIFFS ? "spiffs" : "firmware" );
// do some stuff e.g. notify a MQTT server the update completed successfully
if( restart_after ) {
ESP.restart();
}
});
```
### Verified images via signature
You can now sign your firmware image with an RSA public/private key pair and have the ESP32 check if the signature is correct before
it switches over to the new image.
In order to use this feature just set the boolean `validate` to `true` in the constructor. Next create a key-pair to sign your firmware image:
```
openssl genrsa -out priv_key.pem 4096
openssl rsa -in priv_key.pem -pubout > rsa_key.pub
```
Compile your code so you get your OTA update file (e.g. `firmware.bin`). Now it's time to create the signature:
```
# Create signature file
openssl dgst -sign priv_key.pem -keyform PEM -sha256 -out firmware.sign -binary firmware.bin
# throw it all in one file
cat firmware.sign firmware.bin > firmware.img
```
Upload `firmware.img` to your OTA server and point to it in your `firmware.json`
Last step, create an SPIFFS partition with your `rsa_key.pub` in it. The OTA update should not touch this partition during the update. You'll only need to distribute this partition once.
On the next update-check the ESP32 will download the `firmware.img` extract the first 512 bytes with the signature and check it together with the public key against the new image. If the signature check runs OK, it'll reset into the new firmware.
[#8]: https://github.com/chrisjoyce911/esp32FOTA/issues/8
[#15]: https://github.com/chrisjoyce911/esp32FOTA/issues/15
[#25]: https://github.com/chrisjoyce911/esp32FOTA/issues/25
[#26]: https://github.com/chrisjoyce911/esp32FOTA/issues/26
[#60]: https://github.com/chrisjoyce911/esp32FOTA/issues/60
[#65]: https://github.com/chrisjoyce911/esp32FOTA/issues/65
[#74]: https://github.com/chrisjoyce911/esp32FOTA/issues/74
[#47]: https://github.com/chrisjoyce911/esp32FOTA/pull/47
[#79]: https://github.com/chrisjoyce911/esp32FOTA/pull/79
[#91]: https://github.com/chrisjoyce911/esp32FOTA/pull/91
[#92]: https://github.com/chrisjoyce911/esp32FOTA/pull/92
### Libraries
This library relies on [semver.c by h2non](https://github.com/h2non/semver.c) for semantic versioning support. semver.c is licensed under [MIT](https://github.com/h2non/semver.c/blob/master/LICENSE).
Optional dependencies (zlib/gzip support):
* [esp32-flashz](https://github.com/vortigont/esp32-flashz)
* [esp32-targz](https://github.com/tobozo/ESP32-targz)
### Thanks to
* @nuclearcat
* @thinksilicon
* @tuan-karma
* @hpsaturn
* @tobozo
* @vortigont

View File

@@ -1,60 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <esp32fota.h>
#include <WiFi.h>
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
const char* manifest_url = "http://server/fota/fota.json";
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = esp32FOTA.execHTTPcheck();
if (updatedNeeded)
{
esp32FOTA.execOTA();
}
delay(2000);
}

View File

@@ -1,71 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS)
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Step 3 : Provide SPIFFS filesystem with root_ca.pem of your webserver
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <Arduino.h>
#include <WiFi.h>
#include <FS.h>
#include <SPIFFS.h>
#include <esp32fota.h>
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
const char* manifest_url = "https://server/fota/fota.json";
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
// Provide spiffs with root_ca.pem to validate server certificate
SPIFFS.begin(true);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.setRootCA( MyRootCA );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = esp32FOTA.execHTTPcheck();
if (updatedNeeded)
{
esp32FOTA.execOTA();
}
delay(2000);
}

View File

@@ -1,65 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS) without having a root cert
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <Arduino.h>
#include <WiFi.h>
#include <FS.h>
#include <SPIFFS.h>
#include <esp32fota.h>
// esp32fota esp32fota("<Type of Firmware for this device>", <this version>, <validate signature>, <allow insecure https>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, false, true);
const char* manifest_url = "http://server/fota/fota.json";
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = esp32FOTA.execHTTPcheck();
if (updatedNeeded)
{
esp32FOTA.execOTA();
}
delay(2000);
}

View File

@@ -1,70 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <Arduino.h>
#include <WiFi.h>
#include <FS.h>
#include <SPIFFS.h>
#include <esp32fota.h>
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, true);
const char* manifest_url = "http://server/fota/fota.json";
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
// Need to provide SPIFFS with rsa_key.pub inside.
SPIFFS.begin( true );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.setPubKey( MyRSAKey );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = esp32FOTA.execHTTPcheck();
if (updatedNeeded)
{
esp32FOTA.execOTA();
}
delay(2000);
}

View File

@@ -1,129 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTPS)
*/
// declare filesystem first !
//#include <SD.h>
//#include <SD_MMC.h>
//#include <SPIFFS.h>
#include <LittleFS.h>
//#include <PSRamFS.h>
//#include <flashz.hpp> // optional esp32-flashz for zlib compressed firmwares
//#include <ESP32-targz.h> // optional ESP32-targz for gzip compressed firmwares
#include <esp32fota.h> // fota pulls WiFi library
// esp32fota settings
const int firmware_version = 1;
#if !defined FOTA_URL
#define FOTA_URL "http://server/fota/fota.json"
#endif
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = false;
// for debug only
const char* description = "Basic example with any filesystem";
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", rsa_key_pub, strlen(rsa_key_pub)+1 );
esp32FOTA FOTA; // empty constructor
bool WiFiConnected()
{
return (WiFi.status() == WL_CONNECTED);
}
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while ( !WiFiConnected() )
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
// Provide filesystem with root_ca.pem to validate server certificate
if( ! LittleFS.begin( false ) ) {
Serial.println("LittleFS Mounting failed, aborting!");
while(1) vTaskDelay(1);
}
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
cfg.root_ca = MyRootCA;
cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
// FOTA.setStatusChecker( WiFiConnected );
// /!\ FOTA.checkURL is deprecated, use setManifestURL( String ) instead
//FOTA.setManifestURL( FOTA_URL );
//FOTA.setRootCA( MyRootCA );
//FOTA.setPubKey( MyRSAKey );
// use this when more than one filesystem is used in the sketch
// FOTA.setCertFileSystem( &SD );
// show progress when an update occurs (e.g. on a TFT display)
FOTA.setProgressCb( [](size_t progress, size_t size) {
if( progress == size || progress == 0 ) Serial.println();
Serial.print(".");
});
// add some custom headers to the http queries
FOTA.setExtraHTTPHeader("Authorization", "Basic <credentials>");
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded)
{
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View File

@@ -1,84 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
on a webserver (HTTPS) without checking for certificate validity
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
to run this sketch, the credentials are still cached :-)
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
exhausted.
*/
#include <ESP32-targz.h> // optional ESP32-targz for gzip compressed firmwares
#include <esp32FOTA.hpp>
#include <debug/test_fota_common.h>
// esp32fota settings
int firmware_version_major = 1;
int firmware_version_minor = 1;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = true;
// for debug only
const char* title = "1.1";
const char* description = "Basic example with no security and no filesystem";
esp32FOTA FOTA;
void setup_wifi()
{
delay(10);
Serial.print("MAC Address ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
//cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
FOTA.handle();
delay(20000);
}

View File

@@ -1,88 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
on a webserver (HTTPS) without checking for certificate validity
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
to run this sketch, the credentials are still cached :-)
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
exhausted.
*/
#include <flashz.hpp> // optional esp32-flashz for gzipped firmwares
#include <esp32FOTA.hpp>
#include <debug/test_fota_common.h>
// esp32fota settings
int firmware_version_major = 1;
int firmware_version_minor = 2;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = true;
// for debug only
const char* title = "1.2";
const char* description = "Basic *gzipped* example with no security and no filesystem";
esp32FOTA FOTA;
void setup_wifi()
{
delay(10);
Serial.print("MAC Address ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
//cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,87 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
on a webserver (HTTPS) without checking for certificate validity
Usage: If the ESP32 had a previous successful WiFi connection, then no need to set the ssid/password
to run this sketch, the credentials are still cached :-)
Sketch 1 will FOTA to Sketch 2, then Sketch 3, and so on until all versions in firmware.json are
exhausted.
*/
#include <esp32FOTA.hpp>
#include <debug/test_fota_common.h>
// esp32fota settings
int firmware_version_major = 1;
int firmware_version_minor = 3;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = true;
// for debug only
const char* title = "1.3";
const char* description = "Basic *gzipped* example with no security and no filesystem";
esp32FOTA FOTA;
void setup_wifi()
{
delay(10);
Serial.print("MAC Address ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
//cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,99 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update firmware from a bin located on a webserver (HTTPS)
while using filesystem to check for certificate validity
*/
#include <SPIFFS.h> // include filesystem **before** esp32fota !!
#include <esp32fota.h>
#include <debug/test_fota_common.h>
// esp32fota settings
int firmware_version_major = 2;
int firmware_version_minor = 0;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = false;
// for debug only
const char* title = "2";
const char* description = "SPIFFS example with security";
esp32FOTA FOTA;
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
void setup_wifi()
{
delay(10);
Serial.print("MAC Address ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
// Provide filesystem with root_ca.pem to validate server certificate
if( ! SPIFFS.begin( false ) ) {
Serial.println("SPIFFS Mounting failed, aborting!");
while(1) vTaskDelay(1);
}
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View File

@@ -1,93 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
on a webserver (HTTPS) while using progmem to check for certificate validity
*/
#include <esp32fota.h>
#include <debug/test_fota_common.h>
#include "root_ca.h"
// esp32fota settings
int firmware_version_major = 3;
int firmware_version_minor = 0;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = false;
const bool disable_security = false;
// for debug only
const char* title = "3";
const char* description = "PROGMEM example with security";
esp32FOTA FOTA;
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
FOTA.setRootCA( MyRootCA );
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
cfg.root_ca = MyRootCA;
//cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,25 +0,0 @@
const char* /*github_*/root_ca = R"ROOT_CA(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)ROOT_CA";

View File

@@ -1,99 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update firmware from a bin located on a webserver (HTTPS)
while using filesystem to check for certificate validity
*/
#include <LittleFS.h> // include filesystem **before** esp32fota !!
#include <esp32fota.h>
#include <debug/test_fota_common.h>
// esp32fota settings
int firmware_version_major = 4;
int firmware_version_minor = 0;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = true;
const bool disable_security = false;
// for debug only
const char* title = "4";
const char* description = "LittleFS example with enforced security";
esp32FOTA FOTA;
CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
// CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
// CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
void setup_wifi()
{
delay(10);
Serial.print("MAC Address ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
// Provide filesystem with root_ca.pem to validate server certificate
if( ! LittleFS.begin( false ) ) {
Serial.println("LittleFS Mounting failed, aborting!");
while(1) vTaskDelay(1);
}
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
cfg.root_ca = MyRootCA;
cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View File

@@ -1,93 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update to both firmware and filesystem from binaries located
on a webserver (HTTPS) while using progmem to check for certificate validity
*/
#include <esp32fota.h>
#include <debug/test_fota_common.h>
#include "root_ca.h"
#include "pub_key.h"
// esp32fota settings
int firmware_version_major = 5;
int firmware_version_minor = 0;
int firmware_version_patch = 0;
// #define FOTA_URL "http://server/fota/fota.json"
const char* firmware_name = "esp32-fota-http";
const bool check_signature = true;
const bool disable_security = false;
// for debug only
const char* title = "5";
const char* description = "PROGMEM example with enforced security";
esp32FOTA FOTA;
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &LittleFS );
// CryptoFileAsset *MyRootCA = new CryptoFileAsset( "/root_ca.pem", &SPIFFS );
CryptoMemAsset *MyRootCA = new CryptoMemAsset("Certificates Chain", root_ca, strlen(root_ca)+1 );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &SPIFFS );
// CryptoFileAsset *MyRSAKey = new CryptoFileAsset( "/rsa_key.pub", &LittleFS );
CryptoMemAsset *MyRSAKey = new CryptoMemAsset("RSA Public Key", pub_key, strlen(pub_key)+1 );
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi ");
Serial.println( WiFi.macAddress() );
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
PrintFOTAInfo();
{
auto cfg = FOTA.getConfig();
cfg.name = (char*)firmware_name;
cfg.manifest_url = (char*)FOTA_URL;
cfg.sem = SemverClass( firmware_version_major, firmware_version_minor, firmware_version_patch );
cfg.check_sig = check_signature;
cfg.unsafe = disable_security;
cfg.root_ca = MyRootCA;
cfg.pub_key = MyRSAKey;
FOTA.setConfig( cfg );
}
FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = FOTA.execHTTPcheck();
if (updatedNeeded) {
FOTA.execOTA();
}
delay(20000);
}

View File

@@ -1,25 +0,0 @@
const char* /*github_*/pub_key = R"ROOT_CA(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)ROOT_CA";

View File

@@ -1,25 +0,0 @@
const char* /*github_*/root_ca = R"ROOT_CA(
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
)ROOT_CA";

View File

@@ -1,20 +0,0 @@
// Just a dummy script prevent an endless OTA loop to occur
// It validates the last step in the test suite by printing a message in the serial.
void setup()
{
Serial.begin( 115200 );
Serial.println();
Serial.println();
Serial.println();
Serial.println("**************************");
Serial.println("Test suite COMPLETE :-)");
Serial.println();
Serial.println();
}
void loop()
{
}

View File

@@ -1,61 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <esp32fota.h>
#include <WiFi.h>
// esp32fota esp32fota("<Type of Firmware for this device>", <this version>, <validate signature>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
const char* manifest_url = "http://server/fota/fota.json";
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
delay(2000);
esp32FOTA.forceUpdate("192.168.0.100", 80, "/fota/esp32-fota-http-2.bin", true ); // check signature: true
// Alternatively, forceUpdate can be called with a complete URL:
//esp32FOTA.forceUpdate("http://192.168.0.100/fota/esp32-fota-http-2.bin", true ); // check signature: true
}

View File

@@ -1,62 +0,0 @@
/**
esp32 firmware OTA
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
Setup:
Step 1 : Set your WiFi (ssid & password)
Step 2 : set esp32fota()
Upload:
Step 1 : Menu > Sketch > Export Compiled Library. The bin file will be saved in the sketch folder (Menu > Sketch > Show Sketch folder)
Step 2 : Upload it to your webserver
Step 3 : Update your firmware JSON file ( see firwmareupdate )
*/
#include <esp32fota.h>
#include <WiFi.h>
// esp32fota esp32fota("<Type of Firme for this device>", <this version>, <validate signature>);
esp32FOTA esp32FOTA("esp32-fota-http", 1, false);
const char* manifest_url = "http://server/fota/fota.json";
void setup_wifi()
{
delay(10);
Serial.print("Connecting to WiFi");
WiFi.begin(); // no WiFi creds in this demo :-)
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(WiFi.localIP());
}
void setup()
{
Serial.begin(115200);
esp32FOTA.setManifestURL( manifest_url );
esp32FOTA.useDeviceId( true );
esp32FOTA.printConfig();
setup_wifi();
}
void loop()
{
bool updatedNeeded = esp32FOTA.execHTTPcheck();
if (updatedNeeded)
{
esp32FOTA.execOTA();
}
delay(2000);
}

View File

@@ -1,7 +0,0 @@
{
"type": "esp32-fota-http",
"version": 2,
"host": "192.168.0.100",
"port": 80,
"bin": "/fota/esp32-fota-http-2.bin"
}

View File

@@ -1,22 +0,0 @@
#######################################
# Syntax Coloring Map For esp32FOTA
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
esp32FOTA KEYWORD1
useDeviceID KEYWORD1
checkURL KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
execOTA KEYWORD2
execHTTPcheck KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -1,30 +0,0 @@
{
"name": "esp32FOTA",
"version": "0.2.7",
"keywords": "firmware, OTA, Over The Air Updates, ArduinoOTA",
"description": "Allows for firmware to be updated from a webserver, the device can check for updates at any time. Uses a simple JSON file to outline if a new firmware is avaiable.",
"examples": "examples/*/*.ino",
"repository": {
"type": "git",
"url": "https://github.com/chrisjoyce911/esp32FOTA.git"
},
"authors": [
{
"name": "Chris Joyce",
"email": "chris@joyce.id.au",
"url": "https://github.com/chrisjoyce911",
"maintainer": true
}
],
"frameworks": "arduino",
"headers": "esp32FOTA.hpp",
"platforms": [
"esp32",
"espressif32"
],
"dependencies": [
"WiFiClientSecure",
"HTTPClient",
"ArduinoJson"
]
}

View File

@@ -1,11 +0,0 @@
name=esp32FOTA
version=0.2.7
author=Chris Joyce
maintainer=Chris Joyce <chris@joyce.id.au>
sentence=A simple library for firmware OTA updates
paragraph=Allows for firmware to be updated from a webserver, the device can check for updates at any time. Uses a simple JSON file to outline if a new firmware is available.
category=Communication
url=https://github.com/chrisjoyce911/esp32FOTA
architectures=esp32,espressif32
includes=esp32FOTA.hpp
depends=ArduinoJson

View File

@@ -1,52 +0,0 @@
; CanAirIO Sensorlib
;
; Full guide and details: https://github.com/kike-canaries/canairio_sensorlib
[platformio]
src_dir = ./tests/
;lib_dir = ./
[env]
framework = arduino
upload_speed = 1500000
monitor_speed = 115200
monitor_filters = time
build_flags =
-D CORE_DEBUG_LEVEL=0
lib_deps =
bblanchon/ArduinoJson @ ^6
esp32FOTA
; vortigont/esp32-flashz
; tobozo/ESP32-targz
[esp32_common]
platform = espressif32
board = esp32dev
framework = ${env.framework}
upload_speed = ${env.upload_speed}
monitor_speed = ${env.monitor_speed}
lib_deps = ${env.lib_deps}
build_flags =
${env.build_flags}
[env:esp32_http]
extends = esp32_common
build_src_filter = -<*> +<test_http>
[env:esp32_http_debug]
extends = esp32_common
build_flags =
-D CORE_DEBUG_LEVEL=4
build_src_filter = -<*> +<test_http>
[env:esp32_https]
extends = esp32_common
build_src_filter = -<*> +<test_https>
[env:esp32_https_debug]
extends = esp32_common
build_flags =
-D CORE_DEBUG_LEVEL=4
build_src_filter = -<*> +<test_https>

View File

@@ -1,50 +0,0 @@
#pragma once
// esp32fota settings
extern int firmware_version_major;
extern int firmware_version_minor;
extern int firmware_version_patch;
#if !defined FOTA_URL
#define FOTA_URL "http://server/fota/fota.json"
#endif
extern const char* firmware_name;
extern const bool check_signature;
extern const bool disable_security;
// for debug only
extern const char* description;
extern const char* title;
extern esp32FOTA FOTA;
const char* fota_debug_fmt = R"DBG_FMT(
***************** STAGE %s *****************
Description : %s
Firmware type : %s
Firmware version : %i.%i.%i
Signature check : %s
TLS Cert check : %s
Compression : %s
********************************************
)DBG_FMT";
void PrintFOTAInfo()
{
Serial.printf( fota_debug_fmt,
title,
description,
firmware_name,
firmware_version_major,
firmware_version_minor,
firmware_version_patch,
check_signature ?"Enabled":"Disabled",
disable_security ?"Disabled":"Enabled",
FOTA.zlibSupported() ?"Enabled":"Disabled"
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,395 +0,0 @@
/*
esp32 firmware OTA
Date: December 2018
Author: Chris Joyce <https://github.com/chrisjoyce911/esp32FOTA/esp32FOTA>
Purpose: Perform an OTA update from a bin located on a webserver (HTTP Only)
Date: 2021-12-21
Author: Moritz Meintker <https://thinksilicon.de>
Remarks: Re-written/removed a bunch of functions around HTTPS. The library is
now URL-agnostic. This means if you provide an https://-URL it will
use the root_ca.pem (needs to be provided via PROGMEM/SPIFFS/LittleFS or SD)
to verify the server certificate and then download the ressource through an
encrypted connection unless you set the allow_insecure_https option.
Otherwise it will just use plain HTTP which will still offer to sign
your firmware image.
Date: 2022-09-12
Author: tobozo <https://github.com/tobozo>
Changes:
- Abstracted away filesystem
- Refactored some code blocks
- Added spiffs/littlefs/fatfs updatability
- Made crypto assets (pub key, rootca) loadable from multiple sources
Roadmap:
- Firmware/FlashFS update order (SPIFFS/LittleFS first or last?)
- Archive support for gz/targz formats
- firmware.gz + spiffs.gz in manifest
- bundle.tar.gz [ firmware + filesystem ] in manifest
- Update from Stream (e.g deported update via SD, http or gzupdater)
*/
#pragma once
#define esp32fota_h
extern "C" {
#include "semver/semver.h"
}
#include <map>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <FS.h>
// inherit includes from sketch, detect SPIFFS first for legacy support
#if __has_include(<SPIFFS.h>) || defined _SPIFFS_H_
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "Using SPIFFS for certificate validation"
#endif
#include <SPIFFS.h>
#define FOTA_FS &SPIFFS
#elif __has_include(<LittleFS.h>) || defined _LiffleFS_H_
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "Using LittleFS for certificate validation"
#endif
#include <LittleFS.h>
#define FOTA_FS &LittleFS
#elif __has_include(<SD.h>) || defined _SD_H_
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "Using SD for certificate validation"
#endif
#include <SD.h>
#define FOTA_FS &SD
#elif __has_include(<SD_MMC.h>) || defined _SD_MMC_H_
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "Using SD_MMC for certificate validation"
#endif
#include <SD_MMC.h>
#define FOTA_FS &SD_MMC
#elif defined _LIFFLEFS_H_ // older externally linked, hard to identify and unsupported versions of SPIFFS
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "this version of LittleFS is unsupported, use #include <LittleFS.h> instead, if using platformio add LittleFS(esp32)@^2.0.0 to lib_deps"
#endif
#elif __has_include(<PSRamFS.h>) || defined _PSRAMFS_H_
#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
#pragma message "Using PSRamFS for certificate validation"
#endif
#include <PSRamFS.h>
#define FOTA_FS &PSRamFS
#else
//#if !defined(DISABLE_ALL_LIBRARY_WARNINGS)
// #pragma message "No filesystem provided, certificate validation will be unavailable (hint: include SD, SPIFFS or LittleFS before including this library)"
//#endif
#define FOTA_FS nullptr
#endif
#if __has_include(<flashz.hpp>)
#pragma message "Using FlashZ as Update agent"
#include <flashz.hpp>
#define F_Compression "zlib"
#define F_hasZlib() true
#define F_Update FlashZ::getInstance()
#define F_UpdateEnd() (mode_z ? F_Update.endz() : F_Update.end())
#define F_abort() if (mode_z) F_Update.abortz(); else F_Update.abort()
#define F_writeStream() (mode_z ? F_Update.writezStream(*_stream, updateSize) : F_Update.writeStream(*_stream))
// #define DEBUG_ESP32_FLASHZ
#if !defined DEBUG_ESP32_FLASHZ
#define F_isZlibStream() (_stream->peek() == ZLIB_HEADER && ((partition == U_SPIFFS && _flashFileSystemUrl.indexOf("zz")>-1) || (partition == U_FLASH && _firmwareUrl.indexOf("zz")>-1)))
#define F_canBegin() (mode_z ? F_Update.beginz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition))
#else
__attribute__((unused)) static bool F_canBegin_cb(bool mode_z, int updateSize, int partition) { // implement debug here
return (mode_z ? F_Update.beginz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition));
}
__attribute__((unused)) static bool F_isZlibStream_cb( Stream* stream, int partition, String flashFileSystemUrl, String firmwareUrl ) { // implement debug here
return (stream->peek() == ZLIB_HEADER && ((partition == U_SPIFFS && flashFileSystemUrl.indexOf("zz")>-1) || (partition == U_FLASH && firmwareUrl.indexOf("zz")>-1)));
}
#define F_isZlibStream() F_isZlibStream_cb( _stream, partition, _flashFileSystemUrl, _firmwareUrl )
#define F_canBegin() F_canBegin_cb(mode_z, updateSize, partition)
#endif
#elif __has_include("ESP32-targz.h")
#pragma message "Using GzUpdateClass as Update agent"
#include <ESP32-targz.h>
#define F_Compression "gzip"
#define F_hasZlib() true
#define F_Update GzUpdateClass::getInstance()
#define F_UpdateEnd() (mode_z ? F_Update.endgz() : F_Update.end())
#define F_abort() if (mode_z) F_Update.abortgz(); else F_Update.abort()
#define F_writeStream() (mode_z ? F_Update.writeGzStream(*_stream, updateSize) : F_Update.writeStream(*_stream))
// #define DEBUG_ESP32_TARGZ
#if !defined DEBUG_ESP32_TARGZ
#define F_isZlibStream() (_stream->peek() == 0x1f && ((partition == U_SPIFFS && _flashFileSystemUrl.indexOf("gz")>-1) || (partition == U_FLASH && _firmwareUrl.indexOf("gz")>-1)) )
#define F_canBegin() (mode_z ? F_Update.begingz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition))
#else
__attribute__((unused)) static bool F_canBegin_cb(bool mode_z, int updateSize, int partition) { // implement debug here
return (mode_z ? F_Update.begingz(UPDATE_SIZE_UNKNOWN, partition) : F_Update.begin(updateSize, partition));
}
__attribute__((unused)) static bool F_isZlibStream_cb( Stream* stream, int partition, String flashFileSystemUrl, String firmwareUrl ) { // implement debug here
return (stream->peek() == 0x1f && ((partition == U_SPIFFS && flashFileSystemUrl.indexOf("gz")>-1) || (partition == U_FLASH && firmwareUrl.indexOf("gz")>-1)) );
}
#define F_isZlibStream() F_isZlibStream_cb( _stream, partition, _flashFileSystemUrl, _firmwareUrl )
#define F_canBegin() F_canBegin_cb(mode_z, updateSize, partition)
#endif
#else
#include <Update.h>
#define F_Compression "none"
#define F_Update Update
#define F_hasZlib() false
#define F_isZlibStream() false
#define F_canBegin() F_Update.begin(updateSize, partition)
#define F_UpdateEnd() F_Update.end()
#define F_abort() F_Update.abort()
#define F_writeStream() F_Update.writeStream(*_stream);
#endif
#define FW_SIGNATURE_LENGTH 512
struct SemverClass
{
public:
SemverClass( const char* version );
SemverClass( int major, int minor=0, int patch=0 );
~SemverClass() { semver_free(&_ver); }
semver_t* ver();
private:
semver_t _ver = semver_t();
};
// Filesystem/memory helper for signature check and pem validation.
// This is abstracted away to allow storage alternatives such as
// PROGMEM, SD, SPIFFS, LittleFS or FatFS
// Intended to be used by esp32FOTA.setPubKey() and esp32FOTA.setRootCA()
class CryptoAsset
{
public:
virtual size_t size() = 0;
virtual const char* get() = 0;
};
class CryptoFileAsset : public CryptoAsset
{
public:
CryptoFileAsset( const char* _path, fs::FS* _fs ) : path(_path), fs(_fs), contents(""), len(0) { }
size_t size();
const char* get() { return contents.c_str(); }
private:
const char* path;
fs::FS* fs;
std::string contents;
size_t len;
bool fs_read_file();
};
class CryptoMemAsset : public CryptoAsset
{
public:
CryptoMemAsset( const char* _name, const char* _bytes, size_t _len ) : name(_name), bytes(_bytes), len(_len) { }
size_t size() { return len; };
const char* get() { return bytes; }
private:
const char* name;
const char* bytes;
size_t len;
};
struct FOTAConfig_t
{
char* name { nullptr };
char* manifest_url { nullptr };
SemverClass sem {0};
bool check_sig { false };
bool unsafe { false };
bool use_device_id { false };
CryptoAsset* root_ca { nullptr };
CryptoAsset* pub_key { nullptr };
size_t signature_len {FW_SIGNATURE_LENGTH};
FOTAConfig_t() = default;
};
enum FOTAStreamType_t
{
FOTA_HTTP_STREAM,
FOTA_FILE_STREAM,
FOTA_SERIAL_STREAM
};
// Main Class
class esp32FOTA
{
public:
esp32FOTA();
~esp32FOTA();
esp32FOTA( FOTAConfig_t cfg );
esp32FOTA(const char* firwmareType, int firwmareVersion, bool validate = false, bool allow_insecure_https = false );
esp32FOTA(const String &firwmareType, int firwmareVersion, bool validate = false, bool allow_insecure_https = false )
: esp32FOTA(firwmareType.c_str(), firwmareVersion, validate, allow_insecure_https){};
esp32FOTA(const char* firwmareType, const char* firmwareSemanticVersion, bool validate = false, bool allow_insecure_https = false );
esp32FOTA(const String &firwmareType, const String &firmwareSemanticVersion, bool validate = false, bool allow_insecure_https = false )
: esp32FOTA(firwmareType.c_str(), firmwareSemanticVersion.c_str(), validate, allow_insecure_https){};
template <typename T> void setPubKey( T* asset ) { _cfg.pub_key = (CryptoAsset*)asset; _cfg.check_sig = true; }
template <typename T> void setRootCA( T* asset ) { _cfg.root_ca = (CryptoAsset*)asset; _cfg.unsafe = false; }
bool forceUpdate(const char* firmwareHost, uint16_t firmwarePort, const char* firmwarePath, bool validate );
bool forceUpdate(const char* firmwareURL, bool validate );
bool forceUpdate(bool validate );
bool forceUpdateSPIFFS(const char* firmwareURL, bool validate );
void handle();
bool execOTA();
bool execSPIFFSOTA();
bool execOTA( int partition, bool restart_after = true );
bool execHTTPcheck();
void useDeviceId( bool use=true ) { _cfg.use_device_id = use; }
// config setter
void setConfig( FOTAConfig_t cfg );
void printConfig( FOTAConfig_t *cfg=nullptr );
// Manually specify the manifest url, this is provided as a transition between legagy and new config system
void setManifestURL( const char* manifest_url ) { setString( &_cfg.manifest_url, manifest_url ); }
void setManifestURL( const String &manifest_url ) { setManifestURL( manifest_url.c_str() ); }
// use this to set "Authorization: Basic" or other specific headers to be sent with the queries
void setExtraHTTPHeader( String name, String value ) { extraHTTPHeaders[name] = value; }
// set the signature len
void setSignatureLen( size_t len );
// /!\ Only use this to change filesystem for **default** RootCA and PubKey paths.
// Otherwise use setPubKey() and setRootCA()
void setCertFileSystem( fs::FS *cert_filesystem = nullptr );
// this is passed to Update.onProgress()
typedef std::function<void(size_t,size_t)> ProgressCallback_cb; // size_t progress, size_t size
void setProgressCb(ProgressCallback_cb fn) { onOTAProgress = fn; } // callback setter
// when Update.begin() returned false
typedef std::function<void(int)> UpdateBeginFail_cb; // int partition (U_FLASH or U_SPIFFS)
void setUpdateBeginFailCb(UpdateBeginFail_cb fn) { onUpdateBeginFail = fn; } // callback setter
// after Update.end() and before validate_sig()
typedef std::function<void(int)> UpdateEnd_cb; // int partition (U_FLASH or U_SPIFFS)
void setUpdateEndCb(UpdateEnd_cb fn) { onUpdateEnd = fn; } // callback setter
// validate_sig() error handling, mixed situations
typedef std::function<void(int,int)> UpdateCheckFail_cb; // int partition (U_FLASH or U_SPIFFS), int error_code
void setUpdateCheckFailCb(UpdateCheckFail_cb fn) { onUpdateCheckFail = fn; } // callback setter
// update successful
typedef std::function<void(int,bool)> UpdateFinished_cb; // int partition (U_FLASH or U_SPIFFS), bool restart_after
void setUpdateFinishedCb(UpdateFinished_cb fn) { onUpdateFinished = fn; } // callback setter
// stream getter
typedef std::function<int64_t(esp32FOTA*,int)> getStream_cb; // esp32FOTA* this, int partition (U_FLASH or U_SPIFFS), returns stream size
void setStreamGetter( getStream_cb fn ) { getStream = fn; } // callback setter
// stream ender
typedef std::function<void(esp32FOTA*)> endStream_cb; // esp32FOTA* this
void setStreamEnder( endStream_cb fn ) { endStream = fn; } // callback setter
// connection check
typedef std::function<bool()> isConnected_cb; //
void setStatusChecker( isConnected_cb fn ) { isConnected = fn; } // callback setter
// updating from a File or from Serial?
void setStreamType( FOTAStreamType_t stream_type ) { _stream_type = stream_type; }
void setStreamTimeout( uint32_t timeout ) { _stream_timeout = timeout; }
const char* getManifestURL() { return _manifestUrl.c_str(); }
const char* getFirmwareURL() { return _firmwareUrl.c_str(); }
const char* getFlashFS_URL() { return _flashFileSystemUrl.c_str(); }
const char* getPath(int part) { return part==U_SPIFFS ? getFlashFS_URL() : getFirmwareURL(); }
bool zlibSupported() { return mode_z; }
int getPayloadVersion();
void getPayloadVersion(char * version_string);
FOTAConfig_t getConfig() { return _cfg; };
FOTAStreamType_t getStreamType() { return _stream_type; }
HTTPClient* getHTTPCLient() { return &_http; }
WiFiClientSecure* getWiFiClient() { return &_client; }
fs::File* getFotaFilePtr() { return &_file; }
Stream* getFotaStreamPtr() { return _stream; }
fs::FS* getFotaFS() { return _fs; }
// internals but need to be exposed to the callbacks
bool setupHTTP( const char* url );
void setFotaStream( Stream* stream ) { _stream = stream; }
//[[deprecated("Use setManifestURL( String ) or cfg.manifest_url with setConfig( FOTAConfig_t )")]] String checkURL = "";
//[[deprecated("Use cfg.use_device_id with setConfig( FOTAConfig_t )")]] bool useDeviceID = false;
bool validate_sig( const esp_partition_t* partition, unsigned char *signature, uint32_t firmware_size );
private:
HTTPClient _http;
WiFiClientSecure _client;
Stream *_stream;
fs::File _file;
bool mode_z = F_hasZlib();
FOTAStreamType_t _stream_type = FOTA_HTTP_STREAM; // defaults to HTTP
uint32_t _stream_timeout = 10000; // max wait for stream->available()
void setupStream();
void stopStream();
void setString( char **dest, const char* src ); // mem allocator
FOTAConfig_t _cfg;
SemverClass _payload_sem = SemverClass(0,0,0);
String _manifestUrl;
String _firmwareUrl;
String _flashFileSystemUrl;
fs::FS *_fs = FOTA_FS; // default filesystem for certificate validation
// custom callbacks provided by user
ProgressCallback_cb onOTAProgress; // this is passed to Update.onProgress()
UpdateBeginFail_cb onUpdateBeginFail; // when Update.begin() returned false
UpdateEnd_cb onUpdateEnd; // after Update.end() and before validate_sig()
UpdateCheckFail_cb onUpdateCheckFail; // validate_sig() error handling, mixed situations
UpdateFinished_cb onUpdateFinished; // update successful
getStream_cb getStream; // optional stream getter, defaults to http.getStreamPtr()
endStream_cb endStream; // optional stream closer, defaults to http.end()
isConnected_cb isConnected; // optional connection checker, defaults to WiFi.status()==WL_CONNECTED
std::map<String,String> extraHTTPHeaders; // this holds the extra http headers defined by the user
String getDeviceID();
bool checkJSONManifest(JsonVariant JSONDocument);
void debugSemVer( const char* label, semver_t* version );
void getPartition( int update_partition );
// temporary partition holder for signature check operations
const esp_partition_t* _target_partition = nullptr;
// This is kept for legacy behaviour, use setPubKey() and setRootCA() with
// CryptoMemAsset ot CryptoFileAsset instead
void setupCryptoAssets();
const char* rsa_key_pub_default_path = "/rsa_key.pub";
const char* root_ca_pem_default_path = "/root_ca.pem";
};

View File

@@ -1,14 +0,0 @@
#pragma once
// This is kept for legacy but should not be used in new releases
// as filename an project name don't match (esp32FOTA vs esp32fota)
#ifdef __cplusplus
#include "esp32FOTA.hpp"
#else
#error esp32FOTA requires a C++ compiler, please change file extension to .cc or .cpp
#endif

View File

@@ -1,233 +0,0 @@
# semver.c [![Build Status](https://travis-ci.org/h2non/semver.c.png)](https://travis-ci.org/h2non/semver.c) [![GitHub release](https://img.shields.io/github/tag/h2non/semver.c.svg)](https://github.com/h2non/semver.c/releases)
[Semantic version](http://semver.org) v2.0 parser and render written in [ANSI C](https://en.wikipedia.org/wiki/ANSI_C) with zero dependencies.
## Features
- [x] Standard compliant (otherwise, open an issue)
- [x] Version metadata parsing
- [x] Version prerelease parsing
- [x] Version comparison helpers
- [x] Supports comparison operators
- [x] Version render
- [x] Version bump
- [x] Version sanitizer
- [x] 100% test coverage
- [x] No regexp (ANSI C doesn't support it)
- [x] Numeric conversion for sorting/filtering
## Versions
- [v0](https://github.com/h2non/semver.c/tree/89e66f36544e0250def32640b84b7e15c8585da4) - Legacy version. Beta. Not maintained anymore.
- [v1](https://github.com/h2non/semver.c) - Current stable version.
## Usage
Basic comparison:
```c
#include <stdio.h>
#include <semver.h>
char current[] = "1.5.10";
char compare[] = "2.3.0";
int
main(int argc, char *argv[]) {
semver_t current_version = {};
semver_t compare_version = {};
if (semver_parse(current, &current_version)
|| semver_parse(compare, &compare_version)) {
fprintf(stderr,"Invalid semver string\n");
return -1;
}
int resolution = semver_compare(compare_version, current_version);
if (resolution == 0) {
printf("Versions %s is equal to: %s\n", compare, current);
}
else if (resolution == -1) {
printf("Version %s is lower than: %s\n", compare, current);
}
else {
printf("Version %s is higher than: %s\n", compare, current);
}
// Free allocated memory when we're done
semver_free(&current_version);
semver_free(&compare_version);
return 0;
}
```
Satisfies version:
```c
#include <stdio.h>
#include <semver.h>
semver_t current = {};
semver_t compare = {};
int
main(int argc, char *argv[]) {
semver_parse("1.3.10", &current);
semver_parse("1.5.2", &compare);
// Use caret operator for the comparison
char operator[] = "^";
if (semver_satisfies(current, compare, operator)) {
printf("Version %s can be satisfied by %s", "1.3.10", "1.5.2");
}
// Free allocated memory when we're done
semver_free(&current);
semver_free(&compare);
return 0;
}
```
## Installation
Clone this repository:
```bash
$ git clone https://github.com/h2non/semver.c
```
Or install with [clib](https://github.com/clibs/clib):
```bash
$ clib install h2non/semver.c
```
## API
#### struct semver_t { int major, int minor, int patch, char * prerelease, char * metadata }
semver base struct.
#### semver_parse(const char *str, semver_t *ver) => int
Parses a string as semver expression.
**Returns**:
- `-1` - In case of invalid semver or parsing error.
- `0` - All was fine!
#### semver_compare(semver_t a, semver_t b) => int
Compare versions `a` with `b`.
Returns:
- `-1` in case of lower version.
- `0` in case of equal versions.
- `1` in case of higher version.
#### semver_satisfies(semver_t a, semver_t b, char *operator) => int
Checks if both versions can be satisfied
based on the given comparison operator.
**Allowed operators**:
- `=` - Equality
- `>=` - Higher or equal to
- `<=` - Lower or equal to
- `<` - Lower than
- `>` - Higher than
- `^` - Caret operator comparison ([more info](https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4))
- `~` - Tilde operator comparison ([more info](https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1))
**Returns**:
- `1` - Can be satisfied
- `0` - Cannot be satisfied
#### semver_satisfies_caret(semver_t a, semver_t b) => int
Checks if version `x` can be satisfied by `y`
performing a comparison with caret operator.
See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
**Returns**:
- `1` - Can be satisfied
- `0` - Cannot be satisfied
#### semver_satisfies_patch(semver_t a, semver_t b) => int
Checks if version `x` can be satisfied by `y`
performing a comparison with tilde operator.
See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
**Returns**:
- `1` - Can be satisfied
- `0` - Cannot be satisfied
#### semver_eq(semver_t a, semver_t b) => int
Equality comparison.
#### semver_ne(semver_t a, semver_t b) => int
Non equal comparison.
#### semver_gt(semver_t a, semver_t b) => int
Greater than comparison.
#### semver_lt(semver_t a, semver_t b) => int
Lower than comparison.
#### semver_gte(semver_t a, semver_t b) => int
Greater than or equal comparison.
#### semver_lte(semver_t a, semver_t b) => int
Lower than or equal comparison.
#### semver_render(semver_t *v, char *dest) => void
Render as string.
#### semver_numeric(semver_t *v) => int
Render as numeric value. Useful for ordering and filtering.
#### semver_bump(semver_t *a) => void
Bump major version.
#### semver_bump_minor(semver_t *a) => void
Bump minor version.
#### semver_bump_patch(semver_t *a) => void
Bump patch version.
#### semver_free(semver_t *a) => void
Helper to free allocated memory from heap.
#### semver_is_valid(char *str) => int
Checks if the given string is a valid semver expression.
#### semver_clean(char *str) => int
Removes invalid semver characters in a given string.
## License
MIT - Tomas Aparicio

View File

@@ -1,638 +0,0 @@
/*
* semver.c
*
* Copyright (c) 2015-2017 Tomas Aparicio
* MIT licensed
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "semver.h"
#define SLICE_SIZE 50
#define DELIMITER "."
#define PR_DELIMITER "-"
#define MT_DELIMITER "+"
#define NUMBERS "0123456789"
#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DELIMITERS DELIMITER PR_DELIMITER MT_DELIMITER
#define VALID_CHARS NUMBERS ALPHA DELIMITERS
static const size_t MAX_SIZE = sizeof(char) * 255;
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
/**
* Define comparison operators, storing the
* ASCII code per each symbol in hexadecimal notation.
*/
enum operators {
SYMBOL_GT = 0x3e,
SYMBOL_LT = 0x3c,
SYMBOL_EQ = 0x3d,
SYMBOL_TF = 0x7e,
SYMBOL_CF = 0x5e
};
/**
* Private helpers
*/
/*
* Remove [begin:len-begin] from str by moving len data from begin+len to begin.
* If len is negative cut out to the end of the string.
*/
static int
strcut (char *str, int begin, int len) {
size_t l;
l = strlen(str);
if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
if (len < 0) len = l - begin + 1;
if (begin + len > (int)l) len = l - begin;
memmove(str + begin, str + begin + len, l - len + 1 - begin);
return len;
}
static int
contains (const char c, const char *matrix, size_t len) {
size_t x;
for (x = 0; x < len; x++)
if ((char) matrix[x] == c) return 1;
return 0;
}
static int
has_valid_chars (const char *str, const char *matrix) {
size_t i, len, mlen;
len = strlen(str);
mlen = strlen(matrix);
for (i = 0; i < len; i++)
if (contains(str[i], matrix, mlen) == 0)
return 0;
return 1;
}
static int
binary_comparison (int x, int y) {
if (x == y) return 0;
if (x > y) return 1;
return -1;
}
static int
parse_int (const char *s) {
int valid, num;
valid = has_valid_chars(s, NUMBERS);
if (valid == 0) return -1;
num = strtol(s, NULL, 10);
if (num > MAX_SAFE_INT) return -1;
return num;
}
/*
* Return a string allocated on the heap with the content from sep to end and
* terminate buf at sep.
*/
static char *
parse_slice (char *buf, char sep) {
char *pr, *part;
int plen;
/* Find separator in buf */
pr = strchr(buf, sep);
if (pr == NULL) return NULL;
/* Length from separator to end of buf */
plen = strlen(pr);
/* Copy from buf into new string */
part = (char*)calloc(plen + 1, sizeof(*part));
if (part == NULL) return NULL;
memcpy(part, pr + 1, plen);
/* Null terminate new string */
part[plen] = '\0';
/* Terminate buf where separator was */
*pr = '\0';
return part;
}
/**
* Parses a string as semver expression.
*
* Returns:
*
* `0` - Parsed successfully
* `-1` - In case of error
*/
int
semver_parse (const char *str, semver_t *ver) {
int valid, res;
size_t len;
char *buf;
valid = semver_is_valid(str);
if (!valid) return -1;
len = strlen(str);
buf = (char*)calloc(len + 1, sizeof(*buf));
if (buf == NULL) return -1;
strcpy(buf, str);
ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
res = semver_parse_version(buf, ver);
free(buf);
#if DEBUG > 0
printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
#endif
return res;
}
/**
* Parses a given string as semver expression.
*
* Returns:
*
* `0` - Parsed successfully
* `-1` - Parse error or invalid
*/
int
semver_parse_version (const char *str, semver_t *ver) {
size_t len;
int index, value;
char *slice, *next, *endptr;
slice = (char *) str;
index = 0;
while (slice != NULL && index++ < 4) {
next = strchr(slice, DELIMITER[0]);
if (next == NULL)
len = strlen(slice);
else
len = next - slice;
if (len > SLICE_SIZE) return -1;
/* Cast to integer and store */
value = strtol(slice, &endptr, 10);
if (endptr != next && *endptr != '\0') return -1;
switch (index) {
case 1: ver->major = value; break;
case 2: ver->minor = value; break;
case 3: ver->patch = value; break;
}
/* Continue with the next slice */
if (next == NULL)
slice = NULL;
else
slice = next + 1;
}
return 0;
}
static int
compare_prerelease (char *x, char *y) {
char *lastx, *lasty, *xptr, *yptr, *endptr;
int xlen, ylen, xisnum, yisnum, xnum, ynum;
int xn, yn, min, res;
if (x == NULL && y == NULL) return 0;
if (y == NULL && x) return -1;
if (x == NULL && y) return 1;
lastx = x;
lasty = y;
xlen = strlen(x);
ylen = strlen(y);
while (1) {
if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
xptr = x + xlen;
if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
yptr = y + ylen;
xnum = strtol(lastx, &endptr, 10);
xisnum = endptr == xptr ? 1 : 0;
ynum = strtol(lasty, &endptr, 10);
yisnum = endptr == yptr ? 1 : 0;
if (xisnum && !yisnum) return -1;
if (!xisnum && yisnum) return 1;
if (xisnum && yisnum) {
/* Numerical comparison */
if (xnum != ynum) return xnum < ynum ? -1 : 1;
} else {
/* String comparison */
xn = xptr - lastx;
yn = yptr - lasty;
min = xn < yn ? xn : yn;
if ((res = strncmp(lastx, lasty, min))) return res < 0 ? -1 : 1;
if (xn != yn) return xn < yn ? -1 : 1;
}
lastx = xptr + 1;
lasty = yptr + 1;
if (lastx == x + xlen + 1 && lasty == y + ylen + 1) break;
if (lastx == x + xlen + 1) return -1;
if (lasty == y + ylen + 1) return 1;
}
return 0;
}
int
semver_compare_prerelease (semver_t x, semver_t y) {
return compare_prerelease(x.prerelease, y.prerelease);
}
/**
* Performs a major, minor and patch binary comparison (x, y).
* This function is mostly used internally
*
* Returns:
*
* `0` - If versiona are equal
* `1` - If x is higher than y
* `-1` - If x is lower than y
*/
int
semver_compare_version (semver_t x, semver_t y) {
int res;
if ((res = binary_comparison(x.major, y.major)) == 0) {
if ((res = binary_comparison(x.minor, y.minor)) == 0) {
return binary_comparison(x.patch, y.patch);
}
}
return res;
}
/**
* Compare two semantic versions (x, y).
*
* Returns:
* - `1` if x is higher than y
* - `0` if x is equal to y
* - `-1` if x is lower than y
*/
int
semver_compare (semver_t x, semver_t y) {
int res;
if ((res = semver_compare_version(x, y)) == 0) {
return semver_compare_prerelease(x, y);
}
return res;
}
/**
* Performs a `greater than` comparison
*/
int
semver_gt (semver_t x, semver_t y) {
return semver_compare(x, y) == 1;
}
/**
* Performs a `lower than` comparison
*/
int
semver_lt (semver_t x, semver_t y) {
return semver_compare(x, y) == -1;
}
/**
* Performs a `equality` comparison
*/
int
semver_eq (semver_t x, semver_t y) {
return semver_compare(x, y) == 0;
}
/**
* Performs a `non equal to` comparison
*/
int
semver_neq (semver_t x, semver_t y) {
return semver_compare(x, y) != 0;
}
/**
* Performs a `greater than or equal` comparison
*/
int
semver_gte (semver_t x, semver_t y) {
return semver_compare(x, y) >= 0;
}
/**
* Performs a `lower than or equal` comparison
*/
int
semver_lte (semver_t x, semver_t y) {
return semver_compare(x, y) <= 0;
}
/**
* Checks if version `x` can be satisfied by `y`
* performing a comparison with caret operator.
*
* See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
*
* Returns:
*
* `1` - Can be satisfied
* `0` - Cannot be satisfied
*/
int
semver_satisfies_caret (semver_t x, semver_t y) {
/* Major versions must always match. */
if (x.major == y.major) {
/* If major version is 0, minor versions must match */
if (x.major == 0) {
/* If minor version is 0, patch must match */
if (x.minor == 0){
return (x.minor == y.minor) && (x.patch == y.patch);
}
/* If minor version is not 0, patch must be >= */
else if (x.minor == y.minor){
return x.patch >= y.patch;
}
else{
return 0;
}
}
else if (x.minor > y.minor){
return 1;
}
else if (x.minor == y.minor)
{
return x.patch >= y.patch;
}
else {
return 0;
}
}
return 0;
}
/**
* Checks if version `x` can be satisfied by `y`
* performing a comparison with tilde operator.
*
* See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
*
* Returns:
*
* `1` - Can be satisfied
* `0` - Cannot be satisfied
*/
int
semver_satisfies_patch (semver_t x, semver_t y) {
return x.major == y.major
&& x.minor == y.minor;
}
/**
* Checks if both versions can be satisfied
* based on the given comparison operator.
*
* Allowed operators:
*
* - `=` - Equality
* - `>=` - Higher or equal to
* - `<=` - Lower or equal to
* - `<` - Lower than
* - `>` - Higher than
* - `^` - Caret comparison (see https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4)
* - `~` - Tilde comparison (see https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1)
*
* Returns:
*
* `1` - Can be satisfied
* `0` - Cannot be satisfied
*/
int
semver_satisfies (semver_t x, semver_t y, const char *op) {
int first, second;
/* Extract the comparison operator */
first = op[0];
second = op[1];
/* Caret operator */
if (first == SYMBOL_CF)
return semver_satisfies_caret(x, y);
/* Tilde operator */
if (first == SYMBOL_TF)
return semver_satisfies_patch(x, y);
/* Strict equality */
if (first == SYMBOL_EQ)
return semver_eq(x, y);
/* Greater than or equal comparison */
if (first == SYMBOL_GT) {
if (second == SYMBOL_EQ) {
return semver_gte(x, y);
}
return semver_gt(x, y);
}
/* Lower than or equal comparison */
if (first == SYMBOL_LT) {
if (second == SYMBOL_EQ) {
return semver_lte(x, y);
}
return semver_lt(x, y);
}
return 0;
}
/**
* Free heep allocated memory of a given semver.
* This is just a convenient function that you
* should call when you're done.
*/
void
semver_free (semver_t *x) {
if (x->metadata) {
free(x->metadata);
x->metadata = NULL;
}
if (x->prerelease) {
free(x->prerelease);
x->prerelease = NULL;
}
}
/**
* Renders
*/
static void
concat_num (char * str, int x, const char * sep) {
char buf[SLICE_SIZE] = {0};
if (sep == NULL) sprintf(buf, "%d", x);
else sprintf(buf, "%s%d", sep, x);
strcat(str, buf);
}
static void
concat_char (char * str, char * x, const char * sep) {
char buf[SLICE_SIZE] = {0};
sprintf(buf, "%s%s", sep, x);
strcat(str, buf);
}
/**
* Render a given semver as string
*/
void
semver_render (semver_t *x, char *dest) {
concat_num(dest, x->major, NULL);
concat_num(dest, x->minor, DELIMITER);
concat_num(dest, x->patch, DELIMITER);
if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
}
/**
* Version bump helpers
*/
void
semver_bump (semver_t *x) {
x->major++;
}
void
semver_bump_minor (semver_t *x) {
x->minor++;
}
void
semver_bump_patch (semver_t *x) {
x->patch++;
}
/**
* Helpers
*/
static int
has_valid_length (const char *s) {
return strlen(s) <= MAX_SIZE;
}
/**
* Checks if a given semver string is valid
*
* Returns:
*
* `1` - Valid expression
* `0` - Invalid
*/
int
semver_is_valid (const char *s) {
return has_valid_length(s)
&& has_valid_chars(s, VALID_CHARS);
}
/**
* Removes non-valid characters in the given string.
*
* Returns:
*
* `0` - Valid
* `-1` - Invalid input
*/
int
semver_clean (char *s) {
size_t i, len, mlen;
int res;
if (has_valid_length(s) == 0) return -1;
len = strlen(s);
mlen = strlen(VALID_CHARS);
for (i = 0; i < len; i++) {
if (contains(s[i], VALID_CHARS, mlen) == 0) {
res = strcut(s, i, 1);
if(res == -1) return -1;
--len; --i;
}
}
return 0;
}
static int
char_to_int (const char * str) {
int buf;
size_t i,len, mlen;
buf = 0;
len = strlen(str);
mlen = strlen(VALID_CHARS);
for (i = 0; i < len; i++)
if (contains(str[i], VALID_CHARS, mlen))
buf += (int) str[i];
return buf;
}
/**
* Render a given semver as numeric value.
* Useful for ordering and filtering.
*/
int
semver_numeric (semver_t *x) {
int num;
char buf[SLICE_SIZE * 3];
memset(&buf, 0, SLICE_SIZE * 3);
if (x->major) concat_num(buf, x->major, NULL);
if (x->major || x->minor) concat_num(buf, x->minor, NULL);
if (x->major || x->minor || x->patch) concat_num(buf, x->patch, NULL);
num = parse_int(buf);
if(num == -1) return -1;
if (x->prerelease) num += char_to_int(x->prerelease);
if (x->metadata) num += char_to_int(x->metadata);
return num;
}

View File

@@ -1,62 +0,0 @@
/*
* semver.h
*
* Copyright (c) 2015-2017 Tomas Aparicio
* MIT licensed
*/
#ifndef __SEMVER_H
#define __SEMVER_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef SEMVER_VERSION
#define SEMVER_VERSION "0.2.0"
#endif
/**
* semver_t struct
*/
typedef struct semver_version_s {
int major;
int minor;
int patch;
char * metadata;
char * prerelease;
} semver_t;
/**
* Set prototypes
*/
int semver_satisfies (semver_t x, semver_t y, const char *op);
int semver_satisfies_caret (semver_t x, semver_t y);
int semver_satisfies_patch (semver_t x, semver_t y);
int semver_compare (semver_t x, semver_t y);
int semver_compare_version (semver_t x, semver_t y);
int semver_compare_prerelease (semver_t x, semver_t y);
int semver_gt (semver_t x, semver_t y);
int semver_gte (semver_t x, semver_t y);
int semver_lt (semver_t x, semver_t y);
int semver_lte (semver_t x, semver_t y);
int semver_eq (semver_t x, semver_t y);
int semver_neq (semver_t x, semver_t y);
int semver_parse (const char *str, semver_t *ver);
int semver_parse_version (const char *str, semver_t *ver);
void semver_render (semver_t *x, char *dest);
int semver_numeric (semver_t *x);
void semver_bump (semver_t *x);
void semver_bump_minor (semver_t *x);
void semver_bump_patch (semver_t *x);
void semver_free (semver_t *x);
int semver_is_valid (const char *s);
int semver_clean (char *s);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,117 +0,0 @@
# Shamelessly translated mongsoose 7.13 pack.c to python to provide portability for platformio core software
# perhaps Copyright (c) Cesanta Software Limited, I'm not sure because I'm not a lawyer
# might also be Copyright me or Copyright ChatGPT
# All rights reserved.
# but not sure by whom
# This program is used to pack arbitrary data into a C binary. It takes
# a list of files as an input, and produces a .c data file that contains
# contents of all these files as a collection of byte arrays.
#
# Usage:
# 2. Convert list of files into single .c:
# ./pack file1.data file2.data > fs.c
#
# 3. In your application code, you can access files using this function:
# const char *mg_unpack(const char *file_name, size_t *size);
#
# 4. Build your app with fs.c:
# cc -o my_app my_app.c fs.c
import errno
import sys
import os
import stat
import time
code = """static int scmp(const char *a, const char *b) {
while (*a && (*a == *b)) a++, b++;
return *(const unsigned char *) a - *(const unsigned char *) b;
}
const char *mg_unlist(size_t no) {
return packed_files[no].name;
}
const char *mg_unpack(const char *name, size_t *size, time_t *mtime) {
const struct packed_file *p;
for (p = packed_files; p->name != NULL; p++) {
if (scmp(p->name, name) != 0) continue;
if (size != NULL) *size = p->size - 1;
if (mtime != NULL) *mtime = p->mtime;
return (const char *) p->data;
}
return NULL;
}
"""
def main(argv):
i = 0
strip_prefix = ""
print("#include <stddef.h>")
print("#include <string.h>")
print("#include <time.h>")
print("")
print("#if defined(__cplusplus)\nextern \"C\" {\n#endif")
print("const char *mg_unlist(size_t no);")
print("const char *mg_unpack(const char *, size_t *, time_t *);")
print("#if defined(__cplusplus)\n}\n#endif\n\n", end='')
while i < len(argv):
if argv[i] == "-s":
strip_prefix = argv[i + 1]
i += 2
elif argv[i] == "-h" or argv[i] == "--help":
sys.stderr.write("Usage: %s[-s STRIP_PREFIX] files...\n" % argv[0])
sys.exit(os.EX_USAGE)
else:
ascii = [''] * 12
with open(argv[i], "rb") as fp:
print("static const unsigned char v%d[] = {" % (i + 1))
j = 0
while True:
ch = fp.read(1)
if not ch:
break
ch = ord(ch)
if j == len(ascii):
print(" // %s" % ''.join(ascii))
j = 0
ascii[j] = chr(ch) if ch >= 32 and ch <= 126 and ch != 92 else '.'
print(" %3u," % ch, end='')
j += 1
print(" 0 // %s\n};" % ''.join(ascii))
i += 1
print("")
print("static const struct packed_file {")
print(" const char *name;")
print(" const unsigned char *data;")
print(" size_t size;")
print(" time_t mtime;")
print("} packed_files[] = {")
i = 0
while i < len(argv):
if argv[i] == "-s":
i += 1
continue
st = os.stat(argv[i])
name = argv[i]
n = len(strip_prefix)
if argv[i] == "-s":
i += 1
continue
if name.startswith(strip_prefix):
name = name[n:]
print(" {\"/%s\", v%d, sizeof(v%d), %lu}," % (name, i + 1, i + 1, st.st_mtime))
i += 1
print(" {NULL, NULL, 0, 0}")
print("};\n")
print(code, end='')
if __name__ == "__main__":
main(sys.argv[1:])

View File

@@ -1,34 +0,0 @@
#this script will be run by platformio.ini from its native directory
import os, sys, gzip, shutil
#check for the two files we need to be able to keep updating the firmware by the /update endpoint:
if not os.path.isfile("data/update2.html"):
print("Missing file: data/update2.html")
sys.exit(1)
if os.path.isdir("pack.tmp"):
shutil.rmtree('pack.tmp')
try:
filelist = []
os.makedirs('pack.tmp/data')
# now gzip the stuff except zones.csv since this file is not served by mongoose but directly accessed:
for file in os.listdir("data"):
filename = os.fsdecode(file)
if filename == "zones.csv" or filename == "cert.pem" or filename == "key.pem" or filename == "rsa_key.pub":
shutil.copy('data/' + filename, 'pack.tmp/data/' + filename)
filelist.append('data/' + filename)
continue
else:
with open('data/' + filename, 'rb') as f_in, gzip.open('pack.tmp/data/' + filename + '.gz', 'wb') as f_out:
f_out.writelines(f_in)
filelist.append('data/' + filename + '.gz')
continue
os.chdir('pack.tmp')
cmdstring = 'python ../pack.py ' + ' '.join(filelist)
os.system(cmdstring + '>../src/packed_fs.c')
os.chdir('..')
except Exception as e:
print(f"An error occurred: {str(e)}")
sys.exit(100)
if shutil.rmtree("pack.tmp"):
print("Failed to clean up temporary files")
sys.exit(9)

View File

@@ -1,8 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
ota_0, app, ota_0, 0x10000, 0x1B0000,
ota_1, app, ota_1, 0x1c0000, 0x1B0000,
spiffs, data, spiffs, 0x370000, 0x80000,
coredump, data, coredump,0x3F0000, 64K
# Serialnr, per device key, (wifi) settings are stored in the nvs (arduino: preferences) partition

View File

@@ -1,42 +0,0 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
description = SmartEVSE v3 (ESP32)
default_envs = release
[env]
platform = espressif32 @ 6.6.0
board = esp32dev
framework = arduino
monitor_port = /dev/ttyUSB0
monitor_speed = 115200
upload_speed = 2000000
board_build.f_flash = 80000000L
board_build.flash_mode = dio
lib_ignore =
LittleFS_esp32
lib_deps =
https://github.com/tzapu/WiFiManager.git
miq19/eModbus@1.7.1
bblanchon/ArduinoJson@^6.21.4
monitor_filters = esp32_exception_decoder
board_build.partitions = partitions_custom.csv
extra_scripts = pre:packfs.py
[env:release]
build_flags =
-DCORE_DEBUG_LEVEL=5
-DLOG_LEVEL=5
-DMG_ENABLE_PACKED_FS=1
-DMG_TLS=MG_TLS_MBED
-Wall
-Wextra
-Wunused-variable

View File

@@ -1 +0,0 @@
.pio/build/release

View File

@@ -1,6 +0,0 @@
# This file was automatically generated for projects
# without default 'CMakeLists.txt' file.
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})

View File

@@ -1,341 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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 <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Preferences.h>
#include "evse.h"
#include "utils.h"
#include "OneWire.h"
unsigned char RFID[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned char RFIDlist[600]; // holds up to 100 RFIDs
// ############################# OneWire functions #############################
// Reset 1-Wire device on SW input
// returns: 1 Device found
// 0 No device found
// 255 Error. Line is pulled low (short, or external button pressed?)
//
unsigned char OneWireReset(void) {
unsigned char r;
if (digitalRead(PIN_SW_IN) == LOW) return 255; // Error, pulled low by external device?
ONEWIRE_LOW; // Drive wire low
delayMicroseconds(480);
RTC_ENTER_CRITICAL(); // Disable interrupts
ONEWIRE_FLOATHIGH; // don't drive high, but use pullup
delayMicroseconds(70);
if (digitalRead(PIN_SW_IN) == HIGH) r = 0; // sample pin to see if there is a OneWire device..
else r = 1;
RTC_EXIT_CRITICAL(); // Restore interrupts
delayMicroseconds(410);
return r;
}
void OneWireWriteBit(unsigned char v) {
if (v & 1) { // write a '1'
RTC_ENTER_CRITICAL(); // Disable interrupts
ONEWIRE_LOW; // Drive low
delayMicroseconds(10);
ONEWIRE_HIGH; // Drive high
RTC_EXIT_CRITICAL(); // Restore interrupts
delayMicroseconds(55);
} else { // write a '0'
RTC_ENTER_CRITICAL(); // Disable interrupts
ONEWIRE_LOW; // Drive low
delayMicroseconds(65);
ONEWIRE_HIGH; // Drive high
RTC_EXIT_CRITICAL(); // Restore interrupts
delayMicroseconds(5);
}
}
unsigned char OneWireReadBit(void) {
unsigned char r;
RTC_ENTER_CRITICAL(); // Disable interrupts
ONEWIRE_LOW;
delayMicroseconds(3);
ONEWIRE_FLOATHIGH;
delayMicroseconds(10);
if (digitalRead(PIN_SW_IN) == HIGH) r = 1; // sample pin
else r = 0;
RTC_EXIT_CRITICAL(); // Restore interrupts
delayMicroseconds(53);
return r;
}
void OneWireWrite(unsigned char v) {
unsigned char bitmask;
for (bitmask = 0x01; bitmask ; bitmask <<= 1) {
OneWireWriteBit( (bitmask & v) ? 1u : 0);
}
}
unsigned char OneWireRead(void) {
unsigned char bitmask, r = 0;
for (bitmask = 0x01; bitmask ; bitmask <<= 1) {
if ( OneWireReadBit()) r |= bitmask;
}
return r;
}
#if FAKE_RFID
unsigned char OneWireReadCardId(void) {
if (!RFIDstatus && Show_RFID) { //if ready to accept new card and it is shown
RFID[0] = 0x01; //Family Code
RFID[1] = 0x01; //RFID id = "01 02 03 04 05 06"
RFID[2] = 0x02;
RFID[3] = 0x03;
RFID[4] = 0x04;
RFID[5] = 0x05;
RFID[6] = 0x06;
RFID[7] = 0xf0; //crc8 code TODO is this ok?
Show_RFID = 0; //this makes "showing" the RFID a one shot event
return 1;
}
else
return 0; //card is already read, no new card
}
#else
unsigned char OneWireReadCardId(void) {
unsigned char x;
if (OneWireReset() == 1) { // RFID card detected
OneWireWrite(0x33); // OneWire ReadRom Command
for (x=0 ; x<8 ; x++) RFID[x] = OneWireRead(); // read Family code (0x01) RFID ID (6 bytes) and crc8
if (crc8(RFID,8)) {
RFID[0] = 0; // CRC incorrect, clear first byte of RFID buffer
return 0;
} else {
for (x=1 ; x<7 ; x++) _LOG_A("%02x",RFID[x]);
_LOG_A("\r\n");
return 1;
}
}
return 0;
}
#endif
// ############################## RFID functions ##############################
// Write a list of 20 RFID's to the eeprom
//
void WriteRFIDlist(void) {
if (preferences.begin("RFIDlist", false) ) { // read/write
preferences.putBytes("RFID", RFIDlist, 600); // write 600 bytes to storage
preferences.putUChar("RFIDinit", 2); // data initialized to 600byte mode
preferences.end();
} else {
_LOG_A("Error opening preferences!\n");
}
_LOG_I("\nRFID list saved\n");
}
// Read a list of 20 RFID's from preferences
//
void ReadRFIDlist(void) {
uint8_t initialized = 0;
if (preferences.begin("RFIDlist", true) ) { // read only
initialized = preferences.getUChar("RFIDinit", 0);
switch (initialized) {
case 1: // we were initialized to old 120 bytes mode
preferences.getBytes("RFID", RFIDlist, 120); // read 120 bytes from storage
//we are now going to convert from RFIDlist 120bytes to RFIDlist 600bytes
for (int i = 120; i < 600; i++) RFIDlist[i] = 0xff;
preferences.remove("RFID");
preferences.end();
WriteRFIDlist();
break;
case 0:
DeleteAllRFID(); // when unitialized, delete all cardIDs
setItemValue(MENU_RFIDREADER, 0); // RFID Reader Disabled
break;
case 2: // extended RFIDlist with room for 100tags of 6 bytes = 600 bytes
preferences.getBytes("RFID", RFIDlist, 600); // read 600 bytes from storage
preferences.end();
break;
}
} else {
_LOG_A("Error opening preferences!\n") ;
}
}
// scan for matching RFID in RFIDlist
// returns offset+6 when found, 0 when not found
uint16_t MatchRFID(void) {
uint16_t offset = 0, r;
do {
r = memcmp(RFID + 1, RFIDlist + offset, 6); // compare read RFID with list of stored RFID's
offset += 6;
} while (r !=0 && offset < 594);
if (r == 0) return offset; // return offset + 6 in RFIDlist
else return 0;
}
// Store RFID card in memory and eeprom
// returns 1 when successful
// returns 2 when already stored
// returns 0 when all slots are full.
unsigned char StoreRFID(void) {
uint16_t offset = 0, r;
unsigned char empty[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
// first check if the Card ID was already stored.
if ( MatchRFID() ) return 2; // already stored, that's ok.
do {
r = memcmp(empty, RFIDlist + offset, 6);
offset += 6;
} while (r !=0 && offset < 600);
if (r != 0) return 0; // no more room to store RFID
offset -= 6;
_LOG_A("offset %u ",offset);
memcpy(RFIDlist + offset, RFID+1, 6);
_LOG_I("\nRFIDlist:");
for (r=0; r<600; r++) _LOG_I_NO_FUNC("%02x",RFIDlist[r]);
WriteRFIDlist();
return 1;
}
//load and store parameter RFIDparm into global variable RFID
void LoadandStoreRFID(unsigned int *RFIDparam) {
for (int i = 0; i < 8; i++)
RFID[i]=RFIDparam[i];
StoreRFID();
}
// Delete RFID card in memory and eeprom
// returns 1 when successful, 0 when RFID was not found
unsigned char DeleteRFID(void) {
uint16_t offset = 0, r;
offset = MatchRFID(); // find RFID in list
if (offset) {
offset -= 6;
for (r = 0; r < 6; r++) RFIDlist[offset + r] = 0xff;
} else return 0;
_LOG_A("deleted %u ",offset);
for (r=0; r<600; r++) _LOG_A("%02x",RFIDlist[r]);
WriteRFIDlist();
return 1;
}
void DeleteAllRFID(void) {
uint16_t i;
for (i = 0; i < 600; i++) RFIDlist[i] = 0xff;
WriteRFIDlist();
_LOG_I("All RFID cards erased!\n");
}
void CheckRFID(void) {
uint16_t x;
// When RFID is enabled, a OneWire RFID reader is expected on the SW input
uint8_t RFIDReader = getItemValue(MENU_RFIDREADER);
if (RFIDReader) { // RFID Reader set to Enabled, Learn or Delete
if (OneWireReadCardId() ) { // Read card ID
switch (RFIDReader) {
case 1: // EnableAll. All learned cards accepted for locking /unlocking
x = MatchRFID();
if (x && !RFIDstatus) {
_LOG_A("RFID card found!\n");
if (Access_bit) {
setAccess(false); // Access Off, Switch back to state B1/C1
} else setAccess(true);
RFIDstatus = 1;
} else if (!x) RFIDstatus = 7; // invalid card
BacklightTimer = BACKLIGHT;
break;
case 2: // EnableOne. Only the card that unlocks, can re-lock the EVSE
x = MatchRFID();
if (x && !RFIDstatus) {
_LOG_A("RFID card found!\n");
if (!Access_bit) {
CardOffset = x; // store cardoffset from current card
setAccess(true); // Access On
} else if (CardOffset == x) {
setAccess(false); // Access Off, Switch back to state B1/C1
}
RFIDstatus = 1;
} else if (!x) RFIDstatus = 7; // invalid card
BacklightTimer = BACKLIGHT;
break;
case 3: // Learn Card
x = StoreRFID();
if (x == 1) {
_LOG_A("RFID card stored!\n");
RFIDstatus = 2;
} else if (x == 2 && !RFIDstatus) {
_LOG_A("RFID card was already stored!\n");
RFIDstatus = 4;
} else if (!RFIDstatus) {
_LOG_A("RFID storage full! Delete card first\n");
RFIDstatus = 6;
}
break;
case 4: // Delete Card
x = DeleteRFID();
if (x) {
_LOG_A("RFID card deleted!\n");
RFIDstatus = 3;
} else if (!RFIDstatus) {
_LOG_A("RFID card not in list!\n");
RFIDstatus = 5;
}
break;
default:
break;
}
} else RFIDstatus = 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,266 +0,0 @@
#include "glcd.h"
#ifdef GLCD_FULL_CHARSET
const unsigned char font[0x100][5] = {
#else
const unsigned char font[0x7F][5] = {
#endif
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x00
{0x00, 0x12, 0x1F, 0x10, 0x00}, // 0x01 <20>
{0x00, 0x19, 0x1D, 0x17, 0x12}, // 0x02 <20>
{0x00, 0x11, 0x15, 0x1F, 0x0A}, // 0x03 <20>
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x04
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x05
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x06
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x07
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x08
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x09
{0x08, 0x1C, 0x1C, 0x1C, 0x08}, // 0x0A Energy blob
{0x63, 0x55, 0x49, 0x41, 0x63}, // 0x0B Sum
{0x00, 0x02, 0x05, 0x02, 0x00}, // 0x0C <20>
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0D
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0E
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x0F
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x10
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x11
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x12
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x13
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x14
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x15
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x16
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x17
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x18
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x19
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1A
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1B
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1C
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1D
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1E
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x1F
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 Space
{0x00, 0x00, 0x5F, 0x00, 0x00}, // 0x21 !
{0x00, 0x07, 0x00, 0x07, 0x00}, // 0x22 "
{0x14, 0x7F, 0x14, 0x7F, 0x14}, // 0x23 #
{0x24, 0x2A, 0x7F, 0x2A, 0x12}, // 0x24 $
{0x23, 0x13, 0x08, 0x64, 0x62}, // 0x25 %
{0x36, 0x49, 0x56, 0x20, 0x50}, // 0x26 &
{0x00, 0x08, 0x07, 0x03, 0x00}, // 0x27 '
{0x00, 0x1C, 0x22, 0x41, 0x00}, // 0x28 (
{0x00, 0x41, 0x22, 0x1C, 0x00}, // 0x29 )
{0x2A, 0x1C, 0x7F, 0x1C, 0x2A}, // 0x2A *
{0x08, 0x08, 0x3E, 0x08, 0x08}, // 0x2B +
{0x00, 0x80, 0x70, 0x30, 0x00}, // 0x2C ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // 0x2D -
{0x00, 0x00, 0x60, 0x60, 0x00}, // 0x2E .
{0x20, 0x10, 0x08, 0x04, 0x02}, // 0x2F /
{0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0x30 0
{0x00, 0x42, 0x7F, 0x40, 0x00}, // 0x31 1
{0x72, 0x49, 0x49, 0x49, 0x46}, // 0x32 2
{0x21, 0x41, 0x49, 0x4D, 0x33}, // 0x33 3
{0x18, 0x14, 0x12, 0x7F, 0x10}, // 0x34 4
{0x27, 0x45, 0x45, 0x45, 0x39}, // 0x35 5
{0x3C, 0x4A, 0x49, 0x49, 0x31}, // 0x36 6
{0x41, 0x21, 0x11, 0x09, 0x07}, // 0x37 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 0x38 8
{0x46, 0x49, 0x49, 0x29, 0x1E}, // 0x39 9
{0x00, 0x00, 0x14, 0x00, 0x00}, // 0x3A :
{0x00, 0x40, 0x34, 0x00, 0x00}, // 0x3B ;
{0x00, 0x08, 0x14, 0x22, 0x41}, // 0x3C <
{0x14, 0x14, 0x14, 0x14, 0x14}, // 0x3D =
{0x00, 0x41, 0x22, 0x14, 0x08}, // 0x3E >
{0x02, 0x01, 0x59, 0x09, 0x06}, // 0x3F ?
{0x3E, 0x41, 0x5D, 0x59, 0x4E}, // 0x40 @
{0x7C, 0x12, 0x11, 0x12, 0x7C}, // 0x41 A
{0x7F, 0x49, 0x49, 0x49, 0x36}, // 0x42 B
{0x3E, 0x41, 0x41, 0x41, 0x22}, // 0x43 C
{0x7F, 0x41, 0x41, 0x41, 0x3E}, // 0x44 D
{0x7F, 0x49, 0x49, 0x49, 0x41}, // 0x45 E
{0x7F, 0x09, 0x09, 0x09, 0x01}, // 0x46 F
{0x3E, 0x41, 0x41, 0x51, 0x73}, // 0x47 G
{0x7F, 0x08, 0x08, 0x08, 0x7F}, // 0x48 H
{0x00, 0x41, 0x7F, 0x41, 0x00}, // 0x49 I
{0x20, 0x40, 0x41, 0x3F, 0x01}, // 0x4A J
{0x7F, 0x08, 0x14, 0x22, 0x41}, // 0x4B K
{0x7F, 0x40, 0x40, 0x40, 0x40}, // 0x4C L
{0x7F, 0x02, 0x1C, 0x02, 0x7F}, // 0x4D M
{0x7F, 0x04, 0x08, 0x10, 0x7F}, // 0x4E N
{0x3E, 0x41, 0x41, 0x41, 0x3E}, // 0x4F O
{0x7F, 0x09, 0x09, 0x09, 0x06}, // 0x50 P
{0x3E, 0x41, 0x51, 0x21, 0x5E}, // 0x51 Q
{0x7F, 0x09, 0x19, 0x29, 0x46}, // 0x52 R
{0x26, 0x49, 0x49, 0x49, 0x32}, // 0x53 S
{0x03, 0x01, 0x7F, 0x01, 0x03}, // 0x54 T
{0x3F, 0x40, 0x40, 0x40, 0x3F}, // 0x55 U
{0x1F, 0x20, 0x40, 0x20, 0x1F}, // 0x56 V
{0x3F, 0x40, 0x38, 0x40, 0x3F}, // 0x57 W
{0x63, 0x14, 0x08, 0x14, 0x63}, // 0x58 X
{0x03, 0x04, 0x78, 0x04, 0x03}, // 0x59 Y
{0x61, 0x59, 0x49, 0x4D, 0x43}, // 0x5A Z
{0x00, 0x7F, 0x41, 0x41, 0x41}, // 0x5B [
{0x02, 0x04, 0x08, 0x10, 0x20}, // 0x5C Backslash
{0x00, 0x41, 0x41, 0x41, 0x7F}, // 0x5D ]
{0x04, 0x02, 0x01, 0x02, 0x04}, // 0x5E ^
{0x40, 0x40, 0x40, 0x40, 0x40}, // 0x5F _
{0x00, 0x03, 0x07, 0x08, 0x00}, // 0x60 `
{0x20, 0x54, 0x54, 0x78, 0x40}, // 0x61 a
{0x7F, 0x28, 0x44, 0x44, 0x38}, // 0x62 b
{0x38, 0x44, 0x44, 0x44, 0x28}, // 0x63 c
{0x38, 0x44, 0x44, 0x28, 0x7F}, // 0x64 d
{0x38, 0x54, 0x54, 0x54, 0x18}, // 0x65 e
{0x00, 0x08, 0x7E, 0x09, 0x02}, // 0x66 f
{0x18, 0xA4, 0xA4, 0x9C, 0x78}, // 0x67 g
{0x7F, 0x08, 0x04, 0x04, 0x78}, // 0x68 h
{0x00, 0x44, 0x7D, 0x40, 0x00}, // 0x69 i
{0x20, 0x40, 0x40, 0x3D, 0x00}, // 0x6A j
{0x7F, 0x10, 0x28, 0x44, 0x00}, // 0x6B k
{0x00, 0x41, 0x7F, 0x40, 0x00}, // 0x6C l
{0x7C, 0x04, 0x78, 0x04, 0x78}, // 0x6D m
{0x7C, 0x08, 0x04, 0x04, 0x78}, // 0x6E n
{0x38, 0x44, 0x44, 0x44, 0x38}, // 0x6F o
{0xFC, 0x18, 0x24, 0x24, 0x18}, // 0x70 p
{0x18, 0x24, 0x24, 0x18, 0xFC}, // 0x71 q
{0x7C, 0x08, 0x04, 0x04, 0x08}, // 0x72 r
{0x48, 0x54, 0x54, 0x54, 0x24}, // 0x73 s
{0x04, 0x04, 0x3F, 0x44, 0x24}, // 0x74 t
{0x3C, 0x40, 0x40, 0x20, 0x7C}, // 0x75 u
{0x1C, 0x20, 0x40, 0x20, 0x1C}, // 0x76 v
{0x3C, 0x40, 0x30, 0x40, 0x3C}, // 0x77 w
{0x44, 0x28, 0x10, 0x28, 0x44}, // 0x78 x
{0x4C, 0x90, 0x90, 0x90, 0x7C}, // 0x79 y
{0x44, 0x64, 0x54, 0x4C, 0x44}, // 0x7A z
{0x00, 0x08, 0x36, 0x41, 0x00}, // 0x7B {
{0x00, 0x00, 0x77, 0x00, 0x00}, // 0x7C |
{0x00, 0x41, 0x36, 0x08, 0x00}, // 0x7D }
{0x02, 0x01, 0x02, 0x04, 0x02}, // 0x7E ~
#ifdef GLCD_FULL_CHARSET
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x7F Delete
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x80
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x81
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x82
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x83
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x84
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x85
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x86
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x87
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x88
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x89
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8A
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8B
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8C
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8D
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8E
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x8F
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x90
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x91
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x92
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x93
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x94
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x95
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x96
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x97
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x98
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x99
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9A
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9B
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9C
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9D
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9E
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0x9F
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0xA0
{0x00, 0x00, 0xFA, 0x00, 0x00}, // 0xA1 <20>
{0x3C, 0x24, 0xFF, 0x24, 0x24}, // 0xA2 <20>
{0x48, 0x7E, 0x49, 0x43, 0x66}, // 0xA3 <20>
{0x1C, 0x36, 0x55, 0x41, 0x22}, // 0xA4 <20>
{0x2B, 0x2F, 0xFC, 0x2F, 0x2B}, // 0xA5 <20>
{0x08, 0x55, 0x56, 0x55, 0x20}, // 0xA6 <20>
{0x00, 0x66, 0x89, 0x95, 0x6A}, // 0xA7 <20>
{0x00, 0x59, 0x7A, 0x69, 0x00}, // 0xA8 <20>
{0x38, 0x7C, 0x6C, 0x44, 0x38}, // 0xA9 <20>
{0x26, 0x29, 0x29, 0x2F, 0x28}, // 0xAA <20>
{0x08, 0x14, 0x2A, 0x14, 0x22}, // 0xAB <20>
{0x08, 0x08, 0x08, 0x08, 0x38}, // 0xAC <20>
{0x00, 0x00, 0x00, 0x00, 0x00}, // 0xAD <20>
{0x38, 0x7C, 0x5C, 0x64, 0x38}, // 0xAE <20>
{0x00, 0x01, 0x01, 0x01, 0x00}, // 0xAF <20>
{0x00, 0x02, 0x05, 0x02, 0x00}, // 0xB0 <20>
{0x44, 0x44, 0x5F, 0x44, 0x44}, // 0xB1 <20>
{0x00, 0x19, 0x1D, 0x17, 0x12}, // 0xB2 <20>
{0x00, 0x11, 0x15, 0x1F, 0x0A}, // 0xB3 <20>
{0x44, 0x65, 0x56, 0x4D, 0x44}, // 0xB4 <20>
{0x40, 0x7E, 0x20, 0x1E, 0x20}, // 0xB5 <20>
{0x06, 0x09, 0x7F, 0x01, 0x7F}, // 0xB6 <20>
{0x00, 0x00, 0x08, 0x00, 0x00}, // 0xB7 <20>
{0x00, 0x69, 0x7A, 0x59, 0x00}, // 0xB8 <20>
{0x00, 0x12, 0x1F, 0x10, 0x00}, // 0xB9 <20>
{0x26, 0x29, 0x29, 0x29, 0x26}, // 0xBA <20>
{0x22, 0x14, 0x2A, 0x14, 0x08}, // 0xBB <20>
{0x3E, 0x41, 0x7F, 0x49, 0x41}, // 0xBC <20>
{0x38, 0x44, 0x38, 0x54, 0x18}, // 0xBD <20>
{0x04, 0x09, 0x70, 0x09, 0x04}, // 0xBE <20>
{0x30, 0x48, 0x4D, 0x40, 0x20}, // 0xBF <20>
{0x70, 0x28, 0x25, 0x2A, 0x70}, // 0xC0 <20>
{0x70, 0x2A, 0x25, 0x28, 0x70}, // 0xC1 <20>
{0x70, 0x2A, 0x25, 0x2A, 0x70}, // 0xC2 <20>
{0x70, 0x2A, 0x25, 0x2A, 0x71}, // 0xC3 <20>
{0x70, 0x29, 0x24, 0x29, 0x70}, // 0xC4 <20>
{0x70, 0x28, 0x25, 0x28, 0x70}, // 0xC5 <20>
{0x7C, 0x12, 0x7F, 0x49, 0x41}, // 0xC6 <20>
{0x1E, 0xA1, 0xA1, 0x61, 0x12}, // 0xC7 <20>
{0x7C, 0x54, 0x55, 0x46, 0x00}, // 0xC8 <20>
{0x7C, 0x56, 0x55, 0x44, 0x00}, // 0xC9 <20>
{0x7C, 0x56, 0x55, 0x46, 0x00}, // 0xCA <20>
{0x7C, 0x55, 0x54, 0x45, 0x00}, // 0xCB <20>
{0x00, 0x44, 0x7D, 0x46, 0x00}, // 0xCC <20>
{0x00, 0x46, 0x7D, 0x44, 0x00}, // 0xCD <20>
{0x00, 0x46, 0x7D, 0x46, 0x00}, // 0xCE <20>
{0x00, 0x45, 0x7C, 0x45, 0x00}, // 0xCF <20>
{0x7F, 0x49, 0x41, 0x41, 0x3E}, // 0xD0 <20>
{0x7C, 0x0E, 0x19, 0x32, 0x7D}, // 0xD1 <20>
{0x38, 0x44, 0x45, 0x46, 0x38}, // 0xD2 <20>
{0x38, 0x46, 0x45, 0x44, 0x38}, // 0xD3 <20>
{0x38, 0x46, 0x45, 0x46, 0x38}, // 0xD4 <20>
{0x38, 0x46, 0x45, 0x46, 0x39}, // 0xD5 <20>
{0x38, 0x45, 0x44, 0x45, 0x38}, // 0xD6 <20>
{0x00, 0x14, 0x08, 0x14, 0x00}, // 0xD7 <20>
{0x3C, 0x32, 0x2A, 0x26, 0x1E}, // 0xD8 <20>
{0x3C, 0x40, 0x41, 0x42, 0x3C}, // 0xD9 <20>
{0x3C, 0x42, 0x41, 0x40, 0x3C}, // 0xDA <20>
{0x3C, 0x42, 0x41, 0x42, 0x3C}, // 0xDB <20>
{0x3C, 0x41, 0x40, 0x41, 0x3C}, // 0xDC <20>
{0x04, 0x0A, 0x71, 0x08, 0x04}, // 0xDD <20>
{0x7E, 0x24, 0x24, 0x24, 0x18}, // 0xDE <20>
{0x7C, 0x2A, 0x2A, 0x3E, 0x14}, // 0xDF <20>
{0x20, 0x54, 0x55, 0x7A, 0x40}, // 0xE0 <20>
{0x20, 0x56, 0x55, 0x78, 0x40}, // 0xE1 <20>
{0x20, 0x56, 0x55, 0x7A, 0x40}, // 0xE2 <20>
{0x20, 0x56, 0x55, 0x7A, 0x41}, // 0xE3 <20>
{0x20, 0x55, 0x54, 0x79, 0x40}, // 0xE4 <20>
{0x20, 0x54, 0x55, 0x78, 0x40}, // 0xE5 <20>
{0x20, 0x54, 0x38, 0x54, 0x18}, // 0xE6 <20>
{0x18, 0x3C, 0xA4, 0xE4, 0x24}, // 0xE7 <20>
{0x38, 0x54, 0x55, 0x56, 0x18}, // 0xE8 <20>
{0x38, 0x56, 0x55, 0x54, 0x18}, // 0xE9 <20>
{0x38, 0x56, 0x55, 0x56, 0x18}, // 0xEA <20>
{0x38, 0x55, 0x54, 0x55, 0x18}, // 0xEB <20>
{0x00, 0x44, 0x7D, 0x42, 0x00}, // 0xEC <20>
{0x00, 0x46, 0x7D, 0x40, 0x00}, // 0xED <20>
{0x00, 0x46, 0x7D, 0x42, 0x00}, // 0xEE <20>
{0x00, 0x45, 0x7C, 0x41, 0x00}, // 0xEF <20>
{0x38, 0x45, 0x45, 0x47, 0x38}, // 0xF0 <20>
{0x7C, 0x0A, 0x05, 0x06, 0x79}, // 0xF1 <20>
{0x38, 0x44, 0x45, 0x46, 0x38}, // 0xF2 <20>
{0x38, 0x46, 0x45, 0x44, 0x38}, // 0xF3 <20>
{0x38, 0x46, 0x45, 0x46, 0x38}, // 0xF4 <20>
{0x38, 0x46, 0x45, 0x46, 0x39}, // 0xF5 <20>
{0x38, 0x45, 0x44, 0x45, 0x38}, // 0xF6 <20>
{0x08, 0x08, 0x6B, 0x6B, 0x08}, // 0xF7 <20>
{0x3C, 0x32, 0x2A, 0x26, 0x1E}, // 0xF8 <20>
{0x3C, 0x40, 0x41, 0x22, 0x7C}, // 0xF9 <20>
{0x3C, 0x42, 0x41, 0x20, 0x7C}, // 0xFA <20>
{0x3C, 0x42, 0x41, 0x22, 0x7C}, // 0xFB <20>
{0x3C, 0x41, 0x40, 0x21, 0x7C}, // 0xFC <20>
{0x4C, 0x92, 0x91, 0x90, 0x7C}, // 0xFD <20>
{0xFF, 0x22, 0x22, 0x22, 0x1C}, // 0xFE <20>
{0x4C, 0x91, 0x90, 0x91, 0x7C}, // 0xFF <20>
#endif
};

View File

@@ -1,270 +0,0 @@
#include "glcd.h"
#ifdef GLCD_HIRES_FONT
#ifdef GLCD_FULL_CHARSET
const unsigned char font2[0x100][23] = {
#else
const unsigned char font2[0x7F][23] = {
#endif
{0x0}, // 0x00
{0x0}, // 0x01
{0x0}, // 0x02
{0x0}, // 0x03
{0x0}, // 0x04
{0x0}, // 0x05
{0x0}, // 0x06
{0x0}, // 0x07
{0x0}, // 0x08
{0x0}, // 0x09
{0x0}, // 0x0A
{0x0}, // 0x0B
{0x0}, // 0x0C
{0x0}, // 0x0D
{0x0}, // 0x0E
{0x0}, // 0x0F
{0x0}, // 0x10
{0x0}, // 0x11
{0x0}, // 0x12
{0x0}, // 0x13
{0x0}, // 0x14
{0x0}, // 0x15
{0x0}, // 0x16
{0x0}, // 0x17
{0x0}, // 0x18
{0x0}, // 0x19
{0x0}, // 0x1A
{0x0}, // 0x1B
{0x0}, // 0x1C
{0x0}, // 0x1D
{0x0}, // 0x1E
{0x0}, // 0x1F
{0x3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // 0x20 Space
{0x4, 0x7C, 0x00, 0xFF, 0x33, 0xFF, 0x33, 0x7C, 0x00}, // 0x21 !
{0x6, 0x3C, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x00}, // 0x22 "
{0xB, 0x00, 0x02, 0x10, 0x1E, 0x90, 0x1F, 0xF0, 0x03, 0x7E, 0x02, 0x1E, 0x1E, 0x90, 0x1F, 0xF0, 0x03, 0x7E, 0x02, 0x1E, 0x00, 0x10, 0x00}, // 0x23 #
{0x8, 0x78, 0x04, 0xFC, 0x0C, 0xCC, 0x0C, 0xFF, 0x3F, 0xFF, 0x3F, 0xCC, 0x0C, 0xCC, 0x0F, 0x88, 0x07}, // 0x24 $
{0xB, 0x00, 0x30, 0x38, 0x38, 0x38, 0x1C, 0x38, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x38, 0x70, 0x38, 0x38, 0x38, 0x1C, 0x00}, // 0x25 %
{0x9, 0x00, 0x1F, 0xB8, 0x3F, 0xFC, 0x31, 0xC6, 0x21, 0xE2, 0x37, 0x3E, 0x1E, 0x1C, 0x1C, 0x00, 0x36, 0x00, 0x22}, // 0x26 &
{0x3, 0x27, 0x00, 0x3F, 0x00, 0x1F, 0x00}, // 0x27 '
{0x6, 0xF0, 0x03, 0xFC, 0x0F, 0xFE, 0x1F, 0x07, 0x38, 0x01, 0x20, 0x01, 0x20}, // 0x28 (
{0x6, 0x01, 0x20, 0x01, 0x20, 0x07, 0x38, 0xFE, 0x1F, 0xFC, 0x0F, 0xF0, 0x03}, // 0x29 )
{0x8, 0x98, 0x0C, 0xB8, 0x0E, 0xE0, 0x03, 0xF8, 0x0F, 0xF8, 0x0F, 0xE0, 0x03, 0xB8, 0x0E, 0x98, 0x0C}, // 0x2A *
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xF0, 0x0F, 0xF0, 0x0F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0x2B +
{0x3, 0x00, 0xB8, 0x00, 0xF8, 0x00, 0x78}, // 0x2C ,
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0x2D -
{0x3, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38}, // 0x2E .
{0xB, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00}, // 0x2F /
{0xB, 0xF8, 0x07, 0xFE, 0x1F, 0x06, 0x1E, 0x03, 0x33, 0x83, 0x31, 0xC3, 0x30, 0x63, 0x30, 0x33, 0x30, 0x1E, 0x18, 0xFE, 0x1F, 0xF8, 0x07}, // 0x30 0
{0xB, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0x0C, 0x30, 0x0E, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00}, // 0x31 1
{0xB, 0x1C, 0x30, 0x1E, 0x38, 0x07, 0x3C, 0x03, 0x3E, 0x03, 0x37, 0x83, 0x33, 0xC3, 0x31, 0xE3, 0x30, 0x77, 0x30, 0x3E, 0x30, 0x1C, 0x30}, // 0x32 2
{0xB, 0x0C, 0x0C, 0x0E, 0x1C, 0x07, 0x38, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x39, 0x7E, 0x1F, 0x3C, 0x0E}, // 0x33 3
{0xB, 0xC0, 0x03, 0xE0, 0x03, 0x70, 0x03, 0x38, 0x03, 0x1C, 0x03, 0x0E, 0x03, 0x07, 0x03, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x03, 0x00, 0x03}, // 0x34 4
{0xB, 0x3F, 0x0C, 0x7F, 0x1C, 0x63, 0x38, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0x63, 0x30, 0xE3, 0x38, 0xC3, 0x1F, 0x83, 0x0F}, // 0x35 5
{0xB, 0xC0, 0x0F, 0xF0, 0x1F, 0xF8, 0x39, 0xDC, 0x30, 0xCE, 0x30, 0xC7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x39, 0x80, 0x1F, 0x00, 0x0F}, // 0x36 6
{0xB, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x30, 0x03, 0x3C, 0x03, 0x0F, 0xC3, 0x03, 0xF3, 0x00, 0x3F, 0x00, 0x0F, 0x00, 0x03, 0x00}, // 0x37 7
{0xB, 0x00, 0x0F, 0xBC, 0x1F, 0xFE, 0x39, 0xE7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x30, 0xFE, 0x39, 0xBC, 0x1F, 0x00, 0x0F}, // 0x38 8
{0xB, 0x3C, 0x00, 0x7E, 0x00, 0xE7, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x38, 0xC3, 0x1C, 0xC3, 0x0E, 0xE7, 0x07, 0xFE, 0x03, 0xFC, 0x00}, // 0x39 9
{0x3, 0x70, 0x1C, 0x70, 0x1C, 0x70, 0x1C}, // 0x3A :
{0x3, 0x70, 0x9C, 0x70, 0xFC, 0x70, 0x7C}, // 0x3B ;
{0x8, 0xC0, 0x00, 0xE0, 0x01, 0xF0, 0x03, 0x38, 0x07, 0x1C, 0x0E, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30}, // 0x3C <
{0x9, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06, 0x60, 0x06}, // 0x3D =
{0x8, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0x1C, 0x0E, 0x38, 0x07, 0xF0, 0x03, 0xE0, 0x01, 0xC0, 0x00}, // 0x3E >
{0xA, 0x1C, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0x00, 0x83, 0x37, 0xC3, 0x37, 0xE3, 0x00, 0x77, 0x00, 0x3E, 0x00, 0x1C, 0x00}, // 0x3F ?
{0xB, 0xF8, 0x0F, 0xFE, 0x1F, 0x07, 0x18, 0xF3, 0x33, 0xFB, 0x37, 0x1B, 0x36, 0xFB, 0x37, 0xFB, 0x37, 0x07, 0x36, 0xFE, 0x03, 0xF8, 0x01}, // 0x40 @
{0xA, 0x00, 0x38, 0x00, 0x3F, 0xE0, 0x07, 0xFC, 0x06, 0x1F, 0x06, 0x1F, 0x06, 0xFC, 0x06, 0xE0, 0x07, 0x00, 0x3F, 0x00, 0x38}, // 0x41 A
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xE7, 0x30, 0xFE, 0x39, 0xBC, 0x1F, 0x00, 0x0F}, // 0x42 B
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0x0C, 0x0C}, // 0x43 C
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0x44 D
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0x03, 0x30, 0x03, 0x30}, // 0x45 E
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0x03, 0x00, 0x03, 0x00}, // 0x46 F
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC7, 0x3F, 0xC6, 0x3F}, // 0x47 G
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x48 H
{0x6, 0x03, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30}, // 0x49 I
{0xA, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0xFF, 0x1F, 0xFF, 0x07}, // 0x4A J
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0xE0, 0x01, 0xF0, 0x03, 0x38, 0x07, 0x1C, 0x0E, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30}, // 0x4B K
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30}, // 0x4C L
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0x78, 0x00, 0x1E, 0x00, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x4D M
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x0E, 0x00, 0x38, 0x00, 0xF0, 0x00, 0xC0, 0x03, 0x00, 0x07, 0x00, 0x1C, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x4E N
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0x4F O
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0x83, 0x01, 0xC7, 0x01, 0xFE, 0x00, 0x7C, 0x00}, // 0x50 P
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0x03, 0x36, 0x07, 0x3E, 0x0E, 0x1C, 0xFC, 0x3F, 0xF0, 0x33}, // 0x51 Q
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x83, 0x01, 0x83, 0x01, 0x83, 0x03, 0x83, 0x07, 0x83, 0x0F, 0xC7, 0x1D, 0xFE, 0x38, 0x7C, 0x30}, // 0x52 R
{0xA, 0x3C, 0x0C, 0x7E, 0x1C, 0xE7, 0x38, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30, 0xC7, 0x39, 0x8E, 0x1F, 0x0C, 0x0F}, // 0x53 S
{0x8, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00}, // 0x54 T
{0xA, 0xFF, 0x07, 0xFF, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x38, 0xFF, 0x1F, 0xFF, 0x07}, // 0x55 U
{0xA, 0x07, 0x00, 0x3F, 0x00, 0xF8, 0x01, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x3E, 0xC0, 0x0F, 0xF8, 0x01, 0x3F, 0x00, 0x07, 0x00}, // 0x56 V
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x1C, 0x00, 0x06, 0x80, 0x03, 0x80, 0x03, 0x00, 0x06, 0x00, 0x1C, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x57 W
{0xA, 0x03, 0x30, 0x0F, 0x3C, 0x1C, 0x0E, 0x30, 0x03, 0xE0, 0x01, 0xE0, 0x01, 0x30, 0x03, 0x1C, 0x0E, 0x0F, 0x3C, 0x03, 0x30}, // 0x58 X
{0xA, 0x03, 0x00, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0x00}, // 0x59 Y
{0xA, 0x03, 0x30, 0x03, 0x3C, 0x03, 0x3E, 0x03, 0x33, 0xC3, 0x31, 0xE3, 0x30, 0x33, 0x30, 0x1F, 0x30, 0x0F, 0x30, 0x03, 0x30}, // 0x5A Z
{0x6, 0xFF, 0x3F, 0xFF, 0x3F, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30}, // 0x5B [
{0xB, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x18}, // 0x5C Backslash
{0x6, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x5D ]
{0xB, 0x60, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00}, // 0x5E ^
{0xB, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0}, // 0x5F _
{0x3, 0x3E, 0x00, 0x7E, 0x00, 0x4E, 0x00}, // 0x60 `
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0x61 a
{0xA, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0x62 b
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xC0, 0x18, 0x80, 0x08}, // 0x63 c
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x30, 0xC0, 0x30, 0xFF, 0x3F, 0xFF, 0x3F}, // 0x64 d
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x01}, // 0x65 e
{0x8, 0xC0, 0x00, 0xC0, 0x00, 0xFC, 0x3F, 0xFE, 0x3F, 0xC7, 0x00, 0xC3, 0x00, 0xC3, 0x00, 0x03, 0x00}, // 0x66 f
{0xA, 0x80, 0x03, 0xC0, 0xC7, 0xE0, 0xCE, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xCC, 0x60, 0xE6, 0xE0, 0x7F, 0xE0, 0x3F}, // 0x67 g
{0x9, 0xFF, 0x3F, 0xFF, 0x3F, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x68 h
{0x6, 0x00, 0x30, 0x60, 0x30, 0xEC, 0x3F, 0xEC, 0x3F, 0x00, 0x30, 0x00, 0x30}, // 0x69 i
{0x6, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x60, 0xC0, 0xEC, 0xFF, 0xEC, 0x7F}, // 0x6A j
{0x8, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1C, 0x60, 0x38, 0x00, 0x30}, // 0x6B k
{0x6, 0x00, 0x30, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x00, 0x30, 0x00, 0x30}, // 0x6C l
{0xA, 0xE0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0xE0, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x6D m
{0x9, 0xE0, 0x3F, 0xE0, 0x3F, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x3F, 0x80, 0x3F}, // 0x6E n
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0x6F o
{0xA, 0xE0, 0xFF, 0xE0, 0xFF, 0x60, 0x0C, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0xE0, 0x1C, 0xC0, 0x0F, 0x80, 0x07}, // 0x70 p
{0xA, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1C, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x18, 0x60, 0x0C, 0xE0, 0xFF, 0xE0, 0xFF}, // 0x71 q
{0x9, 0xE0, 0x3F, 0xE0, 0x3F, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xC0, 0x00}, // 0x72 r
{0x8, 0xC0, 0x11, 0xE0, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x33, 0x60, 0x3F, 0x40, 0x1E}, // 0x73 s
{0x8, 0x60, 0x00, 0x60, 0x00, 0xFE, 0x1F, 0xFE, 0x3F, 0x60, 0x30, 0x60, 0x30, 0x60, 0x30, 0x00, 0x30}, // 0x74 t
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0x75 u
{0xA, 0x60, 0x00, 0xE0, 0x01, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x38, 0x00, 0x1E, 0x80, 0x07, 0xE0, 0x01, 0x60, 0x00}, // 0x76 v
{0xA, 0xE0, 0x07, 0xE0, 0x1F, 0x00, 0x38, 0x00, 0x1C, 0xE0, 0x0F, 0xE0, 0x0F, 0x00, 0x1C, 0x00, 0x38, 0xE0, 0x1F, 0xE0, 0x07}, // 0x77 w
{0x9, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x1D, 0x80, 0x0F, 0x00, 0x07, 0x80, 0x0F, 0xC0, 0x1D, 0xE0, 0x38, 0x60, 0x30}, // 0x78 x
{0x8, 0x60, 0x00, 0xE0, 0x81, 0x80, 0xE7, 0x00, 0x7E, 0x00, 0x1E, 0x80, 0x07, 0xE0, 0x01, 0x60, 0x00}, // 0x79 y
{0x9, 0x60, 0x30, 0x60, 0x38, 0x60, 0x3C, 0x60, 0x36, 0x60, 0x33, 0xE0, 0x31, 0xE0, 0x30, 0x60, 0x30, 0x20, 0x30}, // 0x7A z
{0x8, 0x80, 0x00, 0xC0, 0x01, 0xFC, 0x1F, 0x7E, 0x3F, 0x07, 0x70, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60}, // 0x7B {
{0x2, 0xBF, 0x3F, 0xBF, 0x3F}, // 0x7C |
{0x8, 0x03, 0x60, 0x03, 0x60, 0x03, 0x60, 0x07, 0x70, 0x7E, 0x3F, 0xFC, 0x1F, 0xC0, 0x01, 0x80, 0x00}, // 0x7D }
{0xA, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x10, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x04, 0x00}, // 0x7E ~
#ifdef GLCD_FULL_CHARSET
{0xA, 0x00, 0x0F, 0x80, 0x0F, 0xC0, 0x0C, 0x60, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x60, 0x0C, 0xC0, 0x0C, 0x80, 0x0F, 0x00, 0x0F}, // 0x7F Delete
{0x0}, // 0x80
{0x0}, // 0x81
{0x0}, // 0x82
{0x0}, // 0x83
{0x0}, // 0x84
{0x0}, // 0x85
{0x0}, // 0x86
{0x0}, // 0x87
{0x0}, // 0x88
{0x0}, // 0x89
{0x0}, // 0x8A
{0x0}, // 0x8B
{0x0}, // 0x8C
{0x0}, // 0x8D
{0x0}, // 0x8E
{0x0}, // 0x8F
{0x0}, // 0x90
{0x0}, // 0x91
{0x0}, // 0x92
{0x0}, // 0x93
{0x0}, // 0x94
{0x0}, // 0x95
{0x0}, // 0x96
{0x0}, // 0x97
{0x0}, // 0x98
{0x0}, // 0x99
{0x0}, // 0x9A
{0x0}, // 0x9B
{0x0}, // 0x9C
{0x0}, // 0x9D
{0x0}, // 0x9E
{0x0}, // 0x9F
{0x0}, // 0xA0
{0x4, 0x80, 0x0F, 0xF3, 0x3F, 0xF3, 0x3F, 0x80, 0x0F}, // 0xA1 <20>
{0x8, 0xE0, 0x03, 0xF0, 0x07, 0x38, 0x0E, 0xFE, 0x3F, 0xFE, 0x3F, 0x18, 0x0C, 0x38, 0x0E, 0x30, 0x06}, // 0xA2 <20>
{0x9, 0x00, 0x18, 0x80, 0x1C, 0xF8, 0x1F, 0xFC, 0x0B, 0x8C, 0x18, 0x8C, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x00, 0x08}, // 0xA3 <20>
{0x9, 0x20, 0x01, 0xF0, 0x03, 0xFC, 0x0F, 0x2E, 0x1D, 0x27, 0x39, 0x23, 0x31, 0x23, 0x30, 0x07, 0x38, 0x0E, 0x1C}, // 0xA4 <20>
{0xA, 0x03, 0x00, 0x0F, 0x0A, 0x3C, 0x0A, 0xF0, 0x0A, 0xC0, 0x3F, 0xC0, 0x3F, 0xF0, 0x0A, 0x3C, 0x0A, 0x0F, 0x0A, 0x03, 0x00}, // 0xA5 <20>
{0xA, 0x60, 0x0C, 0xF0, 0x1C, 0xF9, 0x39, 0x9B, 0x31, 0x9E, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0xB9, 0x3B, 0x30, 0x1F, 0x20, 0x0E}, // 0xA6 <20>
{0x8, 0xDC, 0x08, 0xFE, 0x19, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0x22, 0x11, 0xE6, 0x1F, 0xC4, 0x0E}, // 0xA7 <20>
{0x8, 0xC0, 0x11, 0xE2, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x3F, 0x40, 0x1E}, // 0xA8 <20>
{0xB, 0xF0, 0x07, 0xF8, 0x0F, 0x1C, 0x1C, 0xCC, 0x19, 0xEC, 0x1B, 0x2C, 0x1A, 0x6C, 0x1B, 0x4C, 0x19, 0x1C, 0x1C, 0xF8, 0x0F, 0xF0, 0x07}, // 0xA9 <20>
{0xA, 0x70, 0x00, 0xFA, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xDB, 0x06, 0xFF, 0x06, 0xFE, 0x00}, // 0xAA <20>
{0x9, 0x80, 0x00, 0xC0, 0x01, 0x60, 0x03, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x01, 0x60, 0x03, 0x20, 0x02}, // 0xAB <20>
{0xA, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0xF8, 0x03, 0xF8, 0x03}, // 0xAC <20>
{0x6, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00}, // 0xAD <20>
{0xB, 0xF0, 0x07, 0xF8, 0x0F, 0x1C, 0x1C, 0xEC, 0x1B, 0xEC, 0x1B, 0xAC, 0x18, 0xEC, 0x1B, 0x4C, 0x1B, 0x1C, 0x1C, 0xF8, 0x0F, 0xF0, 0x07}, // 0xAE <20>
{0x4, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00}, // 0xAF <20>
{0x6, 0x1E, 0x00, 0x3F, 0x00, 0x33, 0x00, 0x33, 0x00, 0x3F, 0x00, 0x1E, 0x00}, // 0xB0 <20>
{0x6, 0xC0, 0x18, 0xC0, 0x18, 0xF0, 0x1B, 0xF0, 0x1B, 0xC0, 0x18, 0xC0, 0x18}, // 0xB1 <20>
{0x5, 0x19, 0x00, 0x1D, 0x00, 0x15, 0x00, 0x17, 0x00, 0x12, 0x00}, // 0xB2 <20>
{0x5, 0x11, 0x00, 0x15, 0x00, 0x15, 0x00, 0x1F, 0x00, 0x0A, 0x00}, // 0xB3 <20>
{0xA, 0x18, 0x30, 0x18, 0x38, 0x19, 0x3C, 0x1B, 0x36, 0x1E, 0x33, 0x9E, 0x31, 0xDB, 0x30, 0x79, 0x30, 0x38, 0x30, 0x18, 0x30}, // 0xB4 <20>
{0x9, 0xF0, 0xFF, 0xF0, 0xFF, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x06, 0xF0, 0x0F, 0xF0, 0x0F}, // 0xB5 <20>
{0xA, 0x38, 0x00, 0x7C, 0x00, 0xC6, 0x00, 0x82, 0x00, 0xFE, 0x3F, 0xFE, 0x3F, 0x02, 0x00, 0xFE, 0x3F, 0xFE, 0x3F, 0x02, 0x00}, // 0xB6 <20>
{0x3, 0x80, 0x01, 0xC0, 0x03, 0x80, 0x01}, // 0xB7 <20>
{0x9, 0x60, 0x30, 0x62, 0x38, 0x66, 0x3C, 0x6C, 0x36, 0x6C, 0x33, 0xE6, 0x31, 0xE2, 0x30, 0x60, 0x30, 0x20, 0x30}, // 0xB8 <20>
{0x3, 0x02, 0x00, 0x1F, 0x00, 0x1F, 0x00}, // 0xB9 <20>
{0xA, 0x3C, 0x00, 0x7E, 0x06, 0xE7, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xC3, 0x06, 0xE7, 0x06, 0x7E, 0x06, 0x3C, 0x00}, // 0xBA <20>
{0x9, 0x20, 0x02, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x20, 0x02, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x00}, // 0xBB <20>
{0xA, 0xF0, 0x03, 0xFC, 0x0F, 0x0E, 0x1C, 0x07, 0x38, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0xC3, 0x30}, // 0xBC <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x60, 0x30, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x01}, // 0xBD <20>
{0xA, 0x08, 0x00, 0x18, 0x00, 0x33, 0x00, 0x63, 0x00, 0xC0, 0x3F, 0xC0, 0x3F, 0x63, 0x00, 0x33, 0x00, 0x18, 0x00, 0x08, 0x00}, // 0xBE <20>
{0xA, 0x00, 0x0E, 0x00, 0x1F, 0x80, 0x3B, 0xC0, 0x31, 0xFB, 0x30, 0x7B, 0x30, 0x00, 0x30, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x0E}, // 0xBF <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE1, 0x0D, 0x7B, 0x0C, 0x7E, 0x0C, 0xE4, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC0 <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE4, 0x0D, 0x7E, 0x0C, 0x7B, 0x0C, 0xE1, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC1 <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x84, 0x0F, 0xE6, 0x0D, 0x7B, 0x0C, 0x7B, 0x0C, 0xE6, 0x0D, 0x84, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC2 <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x82, 0x0F, 0xE3, 0x0D, 0x79, 0x0C, 0x7B, 0x0C, 0xE2, 0x0D, 0x83, 0x0F, 0x01, 0x3E, 0x00, 0x38}, // 0xC3 <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x83, 0x0F, 0xE3, 0x0D, 0x78, 0x0C, 0x78, 0x0C, 0xE3, 0x0D, 0x83, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC4 <20>
{0xA, 0x00, 0x38, 0x00, 0x3E, 0x80, 0x0F, 0xE2, 0x0D, 0x75, 0x0C, 0x75, 0x0C, 0xE2, 0x0D, 0x80, 0x0F, 0x00, 0x3E, 0x00, 0x38}, // 0xC5 <20>
{0xA, 0x00, 0x3C, 0x80, 0x3F, 0xF0, 0x07, 0x7C, 0x06, 0x1F, 0x06, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0xC3, 0x30, 0x03, 0x30}, // 0xC6 <20>
{0xA, 0xF0, 0x01, 0xFC, 0x07, 0x0E, 0xCE, 0x07, 0xDC, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x07, 0x1C, 0x1E, 0x0E, 0x1C, 0x06}, // 0xC7 <20>
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x99, 0x31, 0x9B, 0x31, 0x9E, 0x31, 0x9C, 0x31, 0x98, 0x31, 0x98, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xC8 <20>
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x98, 0x31, 0x98, 0x31, 0x9C, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0x99, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xC9 <20>
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x9C, 0x31, 0x9E, 0x31, 0x9B, 0x31, 0x9B, 0x31, 0x9E, 0x31, 0x9C, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xCA <20>
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x9B, 0x31, 0x9B, 0x31, 0x98, 0x31, 0x98, 0x31, 0x9B, 0x31, 0x9B, 0x31, 0x18, 0x30, 0x18, 0x30}, // 0xCB <20>
{0x6, 0x19, 0x30, 0x1B, 0x30, 0xFE, 0x3F, 0xFC, 0x3F, 0x18, 0x30, 0x18, 0x30}, // 0xCC <20>
{0x6, 0x18, 0x30, 0x18, 0x30, 0xFC, 0x3F, 0xFE, 0x3F, 0x1B, 0x30, 0x19, 0x30}, // 0xCD <20>
{0x6, 0x1C, 0x30, 0x1E, 0x30, 0xFB, 0x3F, 0xFB, 0x3F, 0x1E, 0x30, 0x1C, 0x30}, // 0xCE <20>
{0x6, 0x1B, 0x30, 0x1B, 0x30, 0xF8, 0x3F, 0xF8, 0x3F, 0x1B, 0x30, 0x1B, 0x30}, // 0xCF <20>
{0xA, 0xC0, 0x00, 0xFF, 0x3F, 0xFF, 0x3F, 0xC3, 0x30, 0x03, 0x30, 0x03, 0x30, 0x07, 0x38, 0x0E, 0x1C, 0xFC, 0x0F, 0xF0, 0x03}, // 0xD0 <20>
{0xA, 0xF8, 0x3F, 0xF8, 0x3F, 0x72, 0x00, 0xE3, 0x00, 0xC1, 0x01, 0x83, 0x03, 0x02, 0x07, 0x03, 0x0E, 0xF9, 0x3F, 0xF8, 0x3F}, // 0xD1 <20>
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x39, 0x38, 0x1B, 0x30, 0x1E, 0x30, 0x1C, 0x30, 0x18, 0x30, 0x38, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD2 <20>
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x38, 0x38, 0x18, 0x30, 0x1C, 0x30, 0x1E, 0x30, 0x1B, 0x30, 0x39, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD3 <20>
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3C, 0x38, 0x1E, 0x30, 0x1B, 0x30, 0x1B, 0x30, 0x1E, 0x30, 0x3C, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD4 <20>
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3A, 0x38, 0x1B, 0x30, 0x19, 0x30, 0x1B, 0x30, 0x1A, 0x30, 0x3B, 0x38, 0xF1, 0x1F, 0xE0, 0x0F}, // 0xD5 <20>
{0xA, 0xE0, 0x0F, 0xF0, 0x1F, 0x3B, 0x38, 0x1B, 0x30, 0x18, 0x30, 0x18, 0x30, 0x1B, 0x30, 0x3B, 0x38, 0xF0, 0x1F, 0xE0, 0x0F}, // 0xD6 <20>
{0x8, 0x10, 0x04, 0x30, 0x06, 0x60, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x60, 0x03, 0x30, 0x06, 0x10, 0x04}, // 0xD7 <20>
{0xA, 0xF0, 0x2F, 0xF8, 0x3F, 0x1C, 0x18, 0x0C, 0x3E, 0x8C, 0x37, 0xEC, 0x31, 0x7C, 0x30, 0x18, 0x38, 0xFC, 0x1F, 0xF4, 0x0F}, // 0xD8 <20>
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x01, 0x38, 0x03, 0x30, 0x06, 0x30, 0x04, 0x30, 0x00, 0x30, 0x00, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xD9 <20>
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x00, 0x38, 0x00, 0x30, 0x04, 0x30, 0x06, 0x30, 0x03, 0x30, 0x01, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xDA <20>
{0xA, 0xF8, 0x07, 0xF8, 0x1F, 0x04, 0x38, 0x06, 0x30, 0x03, 0x30, 0x03, 0x30, 0x06, 0x30, 0x04, 0x38, 0xF8, 0x1F, 0xF8, 0x07}, // 0xDB <20>
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x0C, 0x38, 0x0C, 0x30, 0x00, 0x30, 0x00, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xDC <20>
{0xA, 0x08, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC4, 0x3F, 0xC6, 0x3F, 0x63, 0x00, 0x31, 0x00, 0x18, 0x00, 0x08, 0x00}, // 0xDD <20>
{0x8, 0x03, 0x30, 0xFF, 0x3F, 0xFF, 0x3F, 0x1B, 0x36, 0x18, 0x06, 0x18, 0x06, 0xF8, 0x07, 0xF0, 0x03}, // 0xDE <20>
{0x8, 0xC0, 0xFF, 0xE0, 0xFF, 0x30, 0x21, 0x10, 0x21, 0x10, 0x21, 0x30, 0x33, 0xE0, 0x3F, 0xC0, 0x1E}, // 0xDF <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x62, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE0 <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE1 <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE2 <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x68, 0x33, 0x6C, 0x33, 0x64, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x6C, 0x33, 0xE4, 0x3F, 0xC0, 0x3F}, // 0xE3 <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x6C, 0x33, 0x6C, 0x33, 0x60, 0x33, 0x60, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE4 <20>
{0xA, 0x00, 0x1C, 0x40, 0x3E, 0x60, 0x33, 0x64, 0x33, 0x6A, 0x33, 0x6A, 0x33, 0x64, 0x33, 0x60, 0x33, 0xE0, 0x3F, 0xC0, 0x3F}, // 0xE5 <20>
{0xA, 0x80, 0x1C, 0xC0, 0x3E, 0x40, 0x22, 0x40, 0x22, 0xC0, 0x1F, 0x80, 0x3F, 0x40, 0x22, 0x40, 0x22, 0xC0, 0x33, 0x80, 0x11}, // 0xE6 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0xB8, 0x60, 0xB0, 0x60, 0xF0, 0x60, 0xF0, 0x60, 0x30, 0xE0, 0x38, 0xC0, 0x18, 0x80, 0x08}, // 0xE7 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x33, 0x62, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0x60, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xE8 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x3B, 0x60, 0x33, 0x68, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x62, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xE9 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE8, 0x33, 0x6C, 0x33, 0x66, 0x33, 0x66, 0x33, 0x6C, 0x33, 0x68, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xEA <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xEC, 0x33, 0x6C, 0x33, 0x60, 0x33, 0x60, 0x33, 0x6C, 0x33, 0x6C, 0x33, 0xC0, 0x13, 0x80, 0x03}, // 0xEB <20>
{0x6, 0x00, 0x30, 0x62, 0x30, 0xE6, 0x3F, 0xEC, 0x3F, 0x08, 0x30, 0x00, 0x30}, // 0xEC <20>
{0x6, 0x00, 0x30, 0x68, 0x30, 0xEC, 0x3F, 0xE6, 0x3F, 0x02, 0x30, 0x00, 0x30}, // 0xED <20>
{0x6, 0x08, 0x30, 0x6C, 0x30, 0xE6, 0x3F, 0xE6, 0x3F, 0x0C, 0x30, 0x08, 0x30}, // 0xEE <20>
{0x6, 0x0C, 0x30, 0x6C, 0x30, 0xE0, 0x3F, 0xEC, 0x3F, 0x0C, 0x30, 0x00, 0x30}, // 0xEF <20>
{0x6, 0x78, 0x1C, 0xFC, 0x3E, 0xCC, 0x33, 0x8C, 0x33, 0x0C, 0x3F, 0x18, 0x1E}, // 0xF0 <20>
{0x9, 0xE0, 0x3F, 0xE8, 0x3F, 0x6C, 0x00, 0x64, 0x00, 0x6C, 0x00, 0x68, 0x00, 0xEC, 0x00, 0xC4, 0x3F, 0x80, 0x3F}, // 0xF1 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x62, 0x30, 0x66, 0x30, 0x6C, 0x30, 0x68, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF2 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE0, 0x38, 0x68, 0x30, 0x6C, 0x30, 0x66, 0x30, 0x62, 0x30, 0xE0, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF3 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xE8, 0x38, 0x6C, 0x30, 0x66, 0x30, 0x66, 0x30, 0x6C, 0x30, 0xE8, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF4 <20>
{0xA, 0x80, 0x0F, 0xC8, 0x1F, 0xEC, 0x38, 0x64, 0x30, 0x6C, 0x30, 0x68, 0x30, 0x6C, 0x30, 0xE4, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF5 <20>
{0xA, 0x80, 0x0F, 0xC0, 0x1F, 0xEC, 0x38, 0x6C, 0x30, 0x60, 0x30, 0x60, 0x30, 0x6C, 0x30, 0xEC, 0x38, 0xC0, 0x1F, 0x80, 0x0F}, // 0xF6 <20>
{0x8, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xB0, 0x0D, 0xB0, 0x0D, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01}, // 0xF7 <20>
{0xA, 0x80, 0x2F, 0xC0, 0x3F, 0xE0, 0x18, 0x60, 0x3C, 0x60, 0x36, 0x60, 0x33, 0xE0, 0x31, 0xC0, 0x38, 0xE0, 0x1F, 0xA0, 0x0F}, // 0xF8 <20>
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x02, 0x30, 0x06, 0x30, 0x0C, 0x30, 0x08, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xF9 <20>
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x00, 0x38, 0x08, 0x30, 0x0C, 0x30, 0x06, 0x30, 0x02, 0x30, 0x00, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFA <20>
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x08, 0x38, 0x0C, 0x30, 0x06, 0x30, 0x06, 0x30, 0x0C, 0x30, 0x08, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFB <20>
{0xA, 0xE0, 0x0F, 0xE0, 0x1F, 0x0C, 0x38, 0x0C, 0x30, 0x00, 0x30, 0x00, 0x30, 0x0C, 0x30, 0x0C, 0x18, 0xE0, 0x3F, 0xE0, 0x3F}, // 0xFC <20>
{0x8, 0x60, 0x00, 0xE0, 0x81, 0x80, 0xE7, 0x10, 0x7E, 0x18, 0x1E, 0x8C, 0x07, 0xE4, 0x01, 0x60, 0x00}, // 0xFD <20>
{0x8, 0x0C, 0x30, 0xFC, 0x3F, 0xFC, 0x3F, 0x6C, 0x36, 0x60, 0x06, 0x60, 0x06, 0xE0, 0x07, 0xC0, 0x03}, // 0xFE <20>
{0x8, 0x60, 0x00, 0xEC, 0x81, 0x8C, 0xE7, 0x00, 0x7E, 0x00, 0x1E, 0x8C, 0x07, 0xEC, 0x01, 0x60, 0x00}, // 0xFF <20>
#endif
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,690 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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 <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include "ModbusServerRTU.h"
#include "ModbusClientRTU.h"
#include "driver/uart.h"
#include "evse.h"
#include "modbus.h"
#include "utils.h"
extern struct ModBus MB;
// ########################## Modbus helper functions ##########################
/**
* Send single value over modbus
*
* @param uint8_t address
* @param uint8_t function
* @param uint16_t register
* @param uint16_t data
*/
void ModbusSend8(uint8_t address, uint8_t function, uint16_t reg, uint16_t data) {
// 0x12345678 is a token to keep track of modbus requests/responses.
// token: first byte address, second byte function, third and fourth reg
uint32_t token;
token = reg;
token += address << 24;
token += function << 16;
Error err = MBclient.addRequest(token, address, function, reg, data);
if (err!=SUCCESS) {
ModbusError e(err);
_LOG_A("Error creating request: 0x%02x - %s\n", (int)e, (const char *)e);
}
else {
_LOG_V("Sent packet");
}
_LOG_V_NO_FUNC(" address: 0x%02x, function: 0x%02x, reg: 0x%04x, token:0x%08x, data: 0x%04x.\n", address, function, reg, token, data);
}
/**
* Combine Bytes received over modbus
*
* @param pointer to var
* @param pointer to buf
* @param uint8_t pos
* @param uint8_t endianness:\n
* 0: low byte first, low word first (little endian)\n
* 1: low byte first, high word first\n
* 2: high byte first, low word first\n
* 3: high byte first, high word first (big endian)
* @param MBDataType dataType: used to determine how many bytes should be combined
*/
void combineBytes(void *var, uint8_t *buf, uint8_t pos, uint8_t endianness, MBDataType dataType) {
char *pBytes;
pBytes = (char *)var;
// ESP32 is little endian
switch(endianness) {
case ENDIANESS_LBF_LWF: // low byte first, low word first (little endian)
*pBytes++ = (uint8_t)buf[pos + 0];
*pBytes++ = (uint8_t)buf[pos + 1];
if (dataType != MB_DATATYPE_INT16) {
*pBytes++ = (uint8_t)buf[pos + 2];
*pBytes = (uint8_t)buf[pos + 3];
}
break;
case ENDIANESS_LBF_HWF: // low byte first, high word first
if (dataType != MB_DATATYPE_INT16) {
*pBytes++ = (uint8_t)buf[pos + 2];
*pBytes++ = (uint8_t)buf[pos + 3];
}
*pBytes++ = (uint8_t)buf[pos + 0];
*pBytes = (uint8_t)buf[pos + 1];
break;
case ENDIANESS_HBF_LWF: // high byte first, low word first
*pBytes++ = (uint8_t)buf[pos + 1];
*pBytes++ = (uint8_t)buf[pos + 0];
if (dataType != MB_DATATYPE_INT16) {
*pBytes++ = (uint8_t)buf[pos + 3];
*pBytes = (uint8_t)buf[pos + 2];
}
break;
case ENDIANESS_HBF_HWF: // high byte first, high word first (big endian)
if (dataType != MB_DATATYPE_INT16) {
*pBytes++ = (uint8_t)buf[pos + 3];
*pBytes++ = (uint8_t)buf[pos + 2];
}
*pBytes++ = (uint8_t)buf[pos + 1];
*pBytes = (uint8_t)buf[pos + 0];
break;
default:
break;
}
}
// ########################### Modbus main functions ###########################
/**
* Request read holding (FC=3) or read input register (FC=04) to a device over modbus
*
* @param uint8_t address
* @param uint8_t function
* @param uint16_t register
* @param uint16_t quantity
*/
void ModbusReadInputRequest(uint8_t address, uint8_t function, uint16_t reg, uint16_t quantity) {
MB.RequestAddress = address;
MB.RequestFunction = function;
MB.RequestRegister = reg;
ModbusSend8(address, function, reg, quantity);
}
/**
* Response read holding (FC=3) or read input register (FC=04) to a device over modbus
*
* @param uint8_t address
* @param uint8_t function
* @param uint16_t pointer to values
* @param uint8_t count of values
*/
void ModbusReadInputResponse(uint8_t address, uint8_t function, uint16_t *values, uint8_t count) {
_LOG_A("ModbusReadInputResponse, to do!\n");
//ModbusSend(address, function, count * 2u, values, count);
}
/**
* Request write single register (FC=06) to a device over modbus
*
* @param uint8_t address
* @param uint16_t register
* @param uint16_t value
*/
void ModbusWriteSingleRequest(uint8_t address, uint16_t reg, uint16_t value) {
MB.RequestAddress = address;
MB.RequestFunction = 0x06;
MB.RequestRegister = reg;
ModbusSend8(address, 0x06, reg, value);
}
/**
* Request write multiple register (FC=16) to a device over modbus
*
* @param uint8_t address
* @param uint16_t register
* @param uint8_t pointer to data
* @param uint8_t count of data
*/
void ModbusWriteMultipleRequest(uint8_t address, uint16_t reg, uint16_t *values, uint8_t count) {
MB.RequestAddress = address;
MB.RequestFunction = 0x10;
MB.RequestRegister = reg;
// 0x12345678 is a token to keep track of modbus requests/responses.
// token: first byte address, second byte function, third and fourth reg
uint32_t token;
token = reg;
token += address << 24;
token += 0x10 << 16;
Error err = MBclient.addRequest(token, address, 0x10, reg, (uint16_t) count, count * 2u, values);
if (err!=SUCCESS) {
ModbusError e(err);
_LOG_A("Error creating request: 0x%02x - %s\n", (int)e, (const char *)e);
}
_LOG_V("Sent packet address: 0x%02x, function: 0x10, reg: 0x%04x, token: 0x%08x count: %u, values:", address, reg, token, count);
for (uint16_t i = 0; i < count; i++) {
_LOG_V_NO_FUNC(" %04x", values[i]);
}
_LOG_V_NO_FUNC("\n");
}
/**
* Response an exception
*
* @param uint8_t address
* @param uint8_t function
* @param uint8_t exeption
*/
void ModbusException(uint8_t address, uint8_t function, uint8_t exception) {
//uint16_t temp[1];
_LOG_A("ModbusException, to do!\n");
//ModbusSend(address, function, exception, temp, 0);
}
/**
* Decode received modbus packet
*
* @param uint8_t pointer to buffer
* @param uint8_t length of buffer
*/
void ModbusDecode(uint8_t * buf, uint8_t len) {
// Clear old values
MB.Address = 0;
MB.Function = 0;
MB.Register = 0;
MB.RegisterCount = 0;
MB.Value = 0;
MB.DataLength = 0;
MB.Type = MODBUS_INVALID;
MB.Exception = 0;
_LOG_V("Received packet (%i bytes)", len);
for (uint8_t x=0; x<len; x++) {
_LOG_V_NO_FUNC(" %02x", buf[x]);
}
_LOG_V_NO_FUNC("\n");
// Modbus error packets length is 5 bytes
if (len == 3) {
MB.Type = MODBUS_EXCEPTION;
// Modbus device address
MB.Address = buf[0];
// Modbus function
MB.Function = buf[1];
// Modbus Exception code
MB.Exception = buf[2];
_LOG_A("Modbus Exception 0x%02x, Address=0x%02x, Function=0x%02x.\n", MB.Exception, MB.Address, MB.Function);
// Modbus data packets minimum length is 8 bytes
} else if (len >= 6) {
// Modbus device address
MB.Address = buf[0];
// Modbus function
MB.Function = buf[1];
_LOG_V(" valid Modbus packet: Address 0x%02x Function 0x%02x", MB.Address, MB.Function);
switch (MB.Function) {
case 0x03: // (Read holding register)
case 0x04: // (Read input register)
if (len == 6) {
// request packet
MB.Type = MODBUS_REQUEST;
// Modbus register
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
// Modbus register count
MB.RegisterCount = (uint16_t)(buf[4] <<8) | buf[5];
} else {
// Modbus datacount
MB.DataLength = buf[2];
if (MB.DataLength == len - 3) {
// packet length OK
// response packet
MB.Type = MODBUS_RESPONSE;
} else {
_LOG_W("Invalid modbus FC=04 packet\n");
}
}
break;
case 0x06:
// (Write single register)
if (len == 6) {
// request and response packet are the same
MB.Type = MODBUS_OK;
// Modbus register
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
// Modbus register count
MB.RegisterCount = 1;
// value
MB.Value = (uint16_t)(buf[4] <<8) | buf[5];
} else {
_LOG_W("Invalid modbus FC=06 packet\n");
}
break;
case 0x10:
// (Write multiple register))
// Modbus register
MB.Register = (uint16_t)(buf[2] <<8) | buf[3];
// Modbus register count
MB.RegisterCount = (uint16_t)(buf[4] <<8) | buf[5];
if (len == 6) {
// response packet
MB.Type = MODBUS_RESPONSE;
} else {
// Modbus datacount
MB.DataLength = buf[6];
if (MB.DataLength == len - 7) {
// packet length OK
// request packet
MB.Type = MODBUS_REQUEST;
} else {
_LOG_W("Invalid modbus FC=16 packet\n");
}
}
break;
default:
break;
}
// MB.Data
if (MB.Type && MB.DataLength) {
// Set pointer to Data
MB.Data = buf;
// Modbus data is always at the end ahead the checksum
MB.Data = MB.Data + (len - MB.DataLength);
}
// Request - Response check
switch (MB.Type) {
case MODBUS_REQUEST:
MB.RequestAddress = MB.Address;
MB.RequestFunction = MB.Function;
MB.RequestRegister = MB.Register;
break;
case MODBUS_RESPONSE:
// If address and function identical with last send or received request, it is a valid response
if (MB.Address == MB.RequestAddress && MB.Function == MB.RequestFunction) {
if (MB.Function == 0x03 || MB.Function == 0x04)
MB.Register = MB.RequestRegister;
}
MB.RequestAddress = 0;
MB.RequestFunction = 0;
MB.RequestRegister = 0;
break;
case MODBUS_OK:
// If address and function identical with last send or received request, it is a valid response
if (MB.Address == MB.RequestAddress && MB.Function == MB.RequestFunction && MB.Address != BROADCAST_ADR) {
MB.Type = MODBUS_RESPONSE;
MB.RequestAddress = 0;
MB.RequestFunction = 0;
MB.RequestRegister = 0;
} else {
MB.Type = MODBUS_REQUEST;
MB.RequestAddress = MB.Address;
MB.RequestFunction = MB.Function;
MB.RequestRegister = MB.Register;
}
default:
break;
}
}
if(MB.Type) {
_LOG_V_NO_FUNC(" Register 0x%04x", MB.Register);
}
switch (MB.Type) {
case MODBUS_REQUEST:
_LOG_V_NO_FUNC(" Request\n");
break;
case MODBUS_RESPONSE:
_LOG_V_NO_FUNC(" Response\n");
break;
}
}
// ########################### EVSE modbus functions ###########################
/**
* Send measurement request over modbus
*
* @param uint8_t Meter
* @param uint8_t Address
* @param uint16_t Register
* @param uint8_t Count
*/
void requestMeasurement(uint8_t Meter, uint8_t Address, uint16_t Register, uint8_t Count) {
ModbusReadInputRequest(Address, EMConfig[Meter].Function, Register, (EMConfig[Meter].DataType == MB_DATATYPE_INT16 ? Count : (Count * 2u)));
}
/**
* Decode measurement value
*
* @param pointer to buf
* @param uint8_t Count
* @param uint8_t Endianness
* @param MBDataType dataType
* @param signed char Divisor
* @return signed int Measurement
*/
signed int receiveMeasurement(uint8_t *buf, uint8_t Count, uint8_t Endianness, MBDataType dataType, signed char Divisor) {
float dCombined;
signed int lCombined;
if (dataType == MB_DATATYPE_FLOAT32) {
combineBytes(&dCombined, buf, Count * (dataType == MB_DATATYPE_INT16 ? 2u : 4u), Endianness, dataType);
if (Divisor >= 0) {
lCombined = (signed int)(dCombined / (signed int)pow_10[(unsigned)Divisor]);
} else {
lCombined = (signed int)(dCombined * (signed int)pow_10[(unsigned)-Divisor]);
}
} else {
combineBytes(&lCombined, buf, Count * (dataType == MB_DATATYPE_INT16 ? 2u : 4u), Endianness, dataType);
if (dataType == MB_DATATYPE_INT16) {
lCombined = (signed int)((int16_t)lCombined); /* sign extend 16bit into 32bit */
}
if (Divisor >= 0) {
lCombined = lCombined / (signed int)pow_10[(unsigned)Divisor];
} else {
lCombined = lCombined * (signed int)pow_10[(unsigned)-Divisor];
}
}
return lCombined;
}
/**
* Send current measurement request over modbus
*
* @param uint8_t Meter
* @param uint8_t Address
*/
void requestCurrentMeasurement(uint8_t Meter, uint8_t Address) {
switch(Meter) {
case EM_API:
break;
case EM_SENSORBOX:
ModbusReadInputRequest(Address, 4, 0, 20);
break;
case EM_EASTRON1P:
case EM_EASTRON3P:
case EM_EASTRON3P_INV:
// Phase 1-3 current: Register 0x06 - 0x0B (unsigned)
// Phase 1-3 power: Register 0x0C - 0x11 (signed)
ModbusReadInputRequest(Address, 4, 0x06, 12);
break;
case EM_ABB:
// Phase 1-3 current: Register 0x5B0C - 0x5B11 (unsigned)
// Phase 1-3 power: Register 0x5B16 - 0x5B1B (signed)
ModbusReadInputRequest(Address, 3, 0x5B0C, 16);
break;
case EM_SOLAREDGE:
// Read 3 Current values + scaling factor
ModbusReadInputRequest(Address, EMConfig[Meter].Function, EMConfig[Meter].IRegister, 4);
break;
case EM_FINDER_7M:
// Phase 1-3 current: Register 2516 - 2521 (unsigned)
// Phase 1-3 power: Register 2530 - 2535 (signed)
ModbusReadInputRequest(Address, 4, 2516, 20);
break;
default:
// Read 3 Current values
requestMeasurement(Meter, Address, EMConfig[Meter].IRegister, 3);
break;
}
}
/**
* Read current measurement from modbus
*
* @param pointer to buf
* @param uint8_t Meter
* @param pointer to Current (mA)
* @return uint8_t error
*/
uint8_t receiveCurrentMeasurement(uint8_t *buf, uint8_t Meter, signed int *var) {
uint8_t x, offset;
// No CAL option in Menu
CalActive = 0;
switch(Meter) {
case EM_API:
break;
case EM_SENSORBOX:
// return immediately if the data contains no new P1 or CT measurement
if (buf[3] == 0) return 0; // error!!
// determine if there is P1 data present, otherwise use CT data
if (buf[3] & 0x80) offset = 4; // P1 data present
else offset = 7; // Use CTs
// offset 16 is Smart meter P1 current
for (x = 0; x < 3; x++) {
// SmartEVSE works with Amps * 10
var[x] = receiveMeasurement(buf, offset + x, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].IDivisor - 3u);
// When using CT's , adjust the measurements with calibration value
if (offset == 7) {
if (x == 0) Iuncal = abs((var[x] / 10)); // Store uncalibrated CT1 measurement (10mA)
var[x] = var[x] * (signed int)ICal / ICAL;
// When MaxMains is set to >100A, it's assumed 200A:50ma CT's are used.
if (getItemValue(MENU_MAINS) > 100) var[x] = var[x] * 2; // Multiply measured currents with 2
// very small negative currents are shown as zero.
if ((var[x] > -1) && (var[x] < 1)) var[x] = 0;
CalActive = 1; // Enable CAL option in Menu
}
}
// Set Sensorbox 2 to 3/4 Wire configuration (and phase Rotation) (v2.16)
if (buf[1] >= 0x10 && offset == 7) {
GridActive = 1; // Enable the GRID menu option
if ((buf[1] & 0x3) != (Grid << 1) && (LoadBl < 2)) ModbusWriteSingleRequest(0x0A, 0x800, Grid << 1);
} else GridActive = 0;
break;
case EM_SOLAREDGE:
{
// Need to handle the extra scaling factor
int scalingFactor = -(int)receiveMeasurement(
buf,
3,
EMConfig[Meter].Endianness,
EMConfig[Meter].DataType,
0
);
// Now decode the three Current values using that scaling factor
for (x = 0; x < 3; x++) {
var[x] = receiveMeasurement(
buf,
x,
EMConfig[Meter].Endianness,
EMConfig[Meter].DataType,
scalingFactor - 3
);
}
break;
}
default:
for (x = 0; x < 3; x++) {
var[x] = receiveMeasurement(
buf,
x,
EMConfig[Meter].Endianness,
EMConfig[Meter].DataType,
EMConfig[Meter].IDivisor - 3
);
}
break;
}
// Get sign from power measurement on some electric meters
switch(Meter) {
case EM_EASTRON1P: // for some reason the EASTRON1P also needs to loop through the 3 var[x]
// if you only loop through x=0, the minus sign of the current is incorrect
// when exporting current
case EM_EASTRON3P:
for (x = 0; x < 3; x++) {
if (receiveMeasurement(buf, x + 3u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
}
break;
case EM_EASTRON3P_INV:
for (x = 0; x < 3; x++) {
if (receiveMeasurement(buf, x + 3u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) > 0) var[x] = -var[x];
}
break;
case EM_ABB:
for (x = 0; x < 3; x++) {
if (receiveMeasurement(buf, x + 5u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
}
break;
case EM_FINDER_7M:
for (x = 0; x < 3; x++) {
if (receiveMeasurement(buf, x + 7u, EMConfig[Meter].Endianness, EMConfig[Meter].DataType, EMConfig[Meter].PDivisor) < 0) var[x] = -var[x];
}
break;
}
// all OK
return 1;
}
/**
* Map a Modbus register to an item ID (MENU_xxx or STATUS_xxx)
*
* @return uint8_t ItemID
*/
uint8_t mapModbusRegister2ItemID() {
uint16_t RegisterStart, ItemStart, Count;
// Register 0x00*: Status
if (MB.Register < (MODBUS_EVSE_STATUS_START + MODBUS_EVSE_STATUS_COUNT)) {
RegisterStart = MODBUS_EVSE_STATUS_START;
ItemStart = STATUS_STATE;
Count = MODBUS_EVSE_STATUS_COUNT;
// Register 0x01*: Node specific configuration
} else if (MB.Register >= MODBUS_EVSE_CONFIG_START && MB.Register < (MODBUS_EVSE_CONFIG_START + MODBUS_EVSE_CONFIG_COUNT)) {
RegisterStart = MODBUS_EVSE_CONFIG_START;
ItemStart = MENU_CONFIG;
Count = MODBUS_EVSE_CONFIG_COUNT;
// Register 0x02*: System configuration (same on all SmartEVSE in a LoadBalancing setup)
} else if (MB.Register >= MODBUS_SYS_CONFIG_START && MB.Register < (MODBUS_SYS_CONFIG_START + MODBUS_SYS_CONFIG_COUNT)) {
RegisterStart = MODBUS_SYS_CONFIG_START;
ItemStart = MENU_MODE;
Count = MODBUS_SYS_CONFIG_COUNT;
} else {
return 0;
}
if (MB.RegisterCount <= (RegisterStart + Count) - MB.Register) {
return (MB.Register - RegisterStart + ItemStart);
} else {
return 0;
}
}
/**
* Read item values and send modbus response
*/
/*
void ReadItemValueResponse(void) {
uint8_t ItemID;
uint8_t i;
uint16_t values[MODBUS_MAX_REGISTER_READ];
ItemID = mapModbusRegister2ItemID();
if (ItemID) {
for (i = 0; i < MB.RegisterCount; i++) {
values[i] = getItemValue(ItemID + i);
}
ModbusReadInputResponse(MB.Address, MB.Function, values, MB.RegisterCount);
} else {
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
}
}
*/
/**
* Write item values and send modbus response
*/
/*
void WriteItemValueResponse(void) {
uint8_t ItemID;
uint8_t OK = 0;
ItemID = mapModbusRegister2ItemID();
if (ItemID) {
OK = setItemValue(ItemID, MB.Value);
}
if (OK && ItemID < STATUS_STATE) write_settings();
if (MB.Address != BROADCAST_ADR || LoadBl == 0) {
if (!ItemID) {
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
} else if (!OK) {
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
} else {
ModbusWriteSingleResponse(MB.Address, MB.Register, MB.Value);
}
}
}
*/
/**
* Write multiple item values and send modbus response
*/
/*
void WriteMultipleItemValueResponse(void) {
uint8_t ItemID;
uint16_t i, OK = 0, value;
ItemID = mapModbusRegister2ItemID();
if (ItemID) {
for (i = 0; i < MB.RegisterCount; i++) {
value = (MB.Data[i * 2] <<8) | MB.Data[(i * 2) + 1];
OK += setItemValue(ItemID + i, value);
}
}
if (OK && ItemID < STATUS_STATE) write_settings();
if (MB.Address != BROADCAST_ADR || LoadBl == 0) {
if (!ItemID) {
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS);
} else if (!OK) {
ModbusException(MB.Address, MB.Function, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE);
} else {
ModbusWriteMultipleResponse(MB.Address, MB.Register, OK);
}
}
}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,150 +0,0 @@
/*
; Project: Smart EVSE
;
;
;
; 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 <Arduino.h>
#include <stdio.h>
#include <stdlib.h>
#include "evse.h"
#include "utils.h"
unsigned long pow_10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
// read Mac, and reverse to ID
uint32_t MacId() {
uint32_t id = 0;
for (int i=0; i<17; i=i+8) {
id |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
}
return id >> 2; // low two bits are unused.
}
unsigned char crc8(unsigned char *buf, unsigned char len) {
unsigned char crc = 0, i, mix, inbyte;
while (len--) {
inbyte = *buf++;
for (i = 8; i; i--) {
mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) crc ^= 0x8C;
inbyte >>= 1;
}
}
return crc;
}
/**
* Calculates 16-bit CRC of given data
* used for Frame Check Sequence on data frame
*
* @param unsigned char pointer to buffer
* @param unsigned char length of buffer
* @return unsigned int CRC
*/
/*
unsigned int crc16(unsigned char *buf, unsigned char len) {
unsigned int pos, crc = 0xffff;
unsigned char i;
// Poly used is x^16+x^15+x^2+x
for (pos = 0; pos < len; pos++) {
crc ^= (unsigned int)buf[pos]; // XOR byte into least sig. byte of crc
for (i = 8; i != 0; i--) { // Loop over each bit
if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001
crc ^= 0xA001;
} else // Else LSB is not set
crc >>= 1; // Just shift right
}
}
return crc;
}
*/
/**
* Insert rounded value into string in printf style
*
* @param pointer to string
* @param string Format
* @param signed long Value to round and insert
* @param unsinged char Divisor where to set decimal point
* @param unsigned char Decimal place count
*/
void sprintfl(char *str, const char *Format, signed long Value, unsigned char Divisor, unsigned char Decimal) {
signed long val;
val = Value / (signed long) pow_10[Divisor - Decimal - 1];
// Round value
if(val < 0) val -= 5;
else val += 5;
val /= 10;
// Split value
if(Decimal > 0) sprintf(str, Format, (signed int) (val / (signed long) pow_10[Decimal]), (unsigned int) (abs(val) % pow_10[Decimal]));
else sprintf(str, Format, (signed int) val);
}
/* triwave8: triangle (sawtooth) wave generator. Useful for
turning a one-byte ever-increasing value into a
one-byte value that oscillates up and down.
input output
0..127 0..254 (positive slope)
128..255 254..0 (negative slope)
*/
unsigned char triwave8(unsigned char in) {
if (in & 0x80) {
in = 255u - in;
}
unsigned char out = in << 1;
return out;
}
unsigned char scale8(unsigned char i, unsigned char scale) {
return (((unsigned int) i) * (1 + (unsigned int) (scale))) >> 8;
}
/* easing functions; see http://easings.net
ease8InOutQuad: 8-bit quadratic ease-in / ease-out function
*/
unsigned char ease8InOutQuad(unsigned char i) {
unsigned char j = i;
if (j & 0x80) {
j = 255u - j;
}
unsigned char jj = scale8(j, j);
unsigned char jj2 = jj << 1;
if (i & 0x80) {
jj2 = 255u - jj2;
}
return jj2;
}

View File

@@ -1,11 +0,0 @@
This directory is intended for PlatformIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html

View File

@@ -1,19 +0,0 @@
FEED="HomeBatteryCurrent"
if [ $# -eq 0 ]; then
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
exit 1
fi
echo "Enter your current in deci-Ampères:"
OLD_CURRENT=20
while true; do
read -t 8 CURRENT
if [ $CURRENT"x" == "x" ]; then
CURRENT=$OLD_CURRENT
else
OLD_CURRENT=$CURRENT
fi
echo $FEED-CURRENT=$CURRENT.
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT
done

View File

@@ -1,22 +0,0 @@
FEED="EVMeter"
if [ $# -eq 0 ]; then
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
exit 1
fi
echo "Enter your current in deci-Ampères:"
OLD_CURRENT=20
#energy in Wh:
ENERGY=0
while true; do
read -t 5 CURRENT
if [ $CURRENT"x" == "x" ]; then
CURRENT=$OLD_CURRENT
else
OLD_CURRENT=$CURRENT
fi
echo $FEED-CURRENT=$CURRENT.
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT:$CURRENT:$CURRENT:11000:$ENERGY
ENERGY=$((ENERGY + 100))
done

View File

@@ -1,20 +0,0 @@
FEED="MainsMeter"
if [ $# -eq 0 ]; then
echo "Usage: $0 4-digit-topic-nr-of-your-smartevse."
exit 1
fi
echo "Enter your current in deci-Ampères:"
OLD_CURRENT=20
while true; do
read -t 1 CURRENT
if [ $CURRENT"x" == "x" ]; then
CURRENT=$OLD_CURRENT
else
OLD_CURRENT=$CURRENT
fi
echo $FEED-CURRENT=$CURRENT.
mosquitto_pub -h 127.0.0.1 -t "SmartEVSE-$1/Set/$FEED" -m $CURRENT:$CURRENT:$CURRENT
sleep 1
done

View File

@@ -1,743 +0,0 @@
#!/bin/bash
# This script is meant to automate testing of SmartEVSEv3 firmware
# Needs jq binary
#serialnrs (4 digits):
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <serialnr_of_master> <serialnr_of_slave> <test_selection> ; serialnr is 4 digits."
echo
echo "Make sure you compiled your test version with -DAUTOMATED_TESTING=1 !!"
echo
echo "Known BUGS: Only run one test at a time; running multiple tests leads to false <fails>"
echo
echo "WARNING: ONLY USE THIS SCRIPT ON SMARTEVSEs ON A TEST BENCH"
echo "NEVER USE THIS SCRIPT ON A LIVE SMARTEVSE; IT _WILL_ BLOW YOUR FUSES AND YOUR BREAKERS!!!"
exit 1
fi
COUNT=`pgrep tests | wc -l`
if [ $COUNT -ne 2 ]; then
echo "Tests are already running in the background, exiting"
killall tests.sh
exit 1
fi
if [ $3 -eq 0 ]; then #all tests selected
SEL=$((0xFFFF))
else
SEL=$3
fi
DBG=1 #1 means debug mode on, 0 means debug mode off
# please give values in deci-Ampère:
MASTER_SOCKET_HARDWIRED=320
SLAVE_SOCKET_HARDWIRED=130
MASTER_MAC_ID=$1
SLAVE_MAC_ID=$2
MASTER="smartevse-"$1".local"
SLAVE="smartevse-"$2".local"
control_c()
# run if user hits control-c
{
echo -en "\n*** Ouch! Exiting ***\n"
#kill all running subprocesses
pkill -P $$
exit $?
}
# trap keyboard interrupt (control-c)
trap control_c SIGINT
#curl suppress data
CURLPOST="curl -s -o /dev/null -X POST -d''"
# Colors for echo
# Reset
NC='\033[0m' # Text Reset
# Regular Colors
Black='\033[0;30m' # Black
Red='\033[0;31m' # Red
Green='\033[0;32m' # Green
Yellow='\033[0;33m' # Yellow
Blue='\033[0;34m' # Blue
Purple='\033[0;35m' # Purple
Cyan='\033[0;36m' # Cyan
White='\033[0;37m' # White
ABORT=0
init_devices () {
for device in $SLAVE $MASTER; do
#go to Normal Mode for init
$CURLPOST $device/reboot
sleep 1
$CURLPOST "$device/automated_testing?loadbl=0&mainsmeter=1"
$CURLPOST $device/settings?mode=1
done
read -p "Make sure all EVSE's are set to NOT CHARGING, then press <ENTER>" dummy
sleep 5
}
init_currents () {
#first load all settings before the test
for device in $SLAVE $MASTER; do
$CURLPOST "$device/automated_testing?config=1&current_max=60&current_max_circuit=70&current_main=80"
$CURLPOST "$device/settings?current_max_sum_mains=600&enable_C2=0"
#$CURLPOST $device/settings?enable_C2=0 #TODO cycle through all tests with different settings !!!
done
}
#takes 3 arguments, actual value, test value and margin
print_results() {
if [ $DBG -eq 1 ]; then
printf "CHARGECUR=$1, TARGET=$2."
fi
if [ $1 -ge $(( $2 - $3 )) ] && [ $1 -le $(( $2 + $3 )) ]; then
printf "$Green Passed $NC LBL=$loadbl_master, Mode=$MODE: $device chargecurrent is limited to $TESTSTRING.\n"
else
printf "$Red Failed $NC LBL=$loadbl_master, Mode=$MODE: $device chargecurrent is $1 dA and should be limited to $2 dA (with a margin of $3 dA) because of $TESTSTRING.\n"
fi
}
#takes 4 arguments, actual value, test value, margin, string_to_test
print_results2() {
if [ $DBG -eq 1 ]; then
printf "$4=$1, TARGET=$2."
fi
if [ $1 -ge $(( $2 - $3 )) ] && [ $1 -le $(( $2 + $3 )) ]; then
printf "$Green Passed $NC LBL=$loadbl_master, Mode=$MODE: $device $4 is as expected when testing $TESTSTRING.\n"
else
printf "$Red Failed $NC LBL=$loadbl_master, Mode=$MODE: $device $4=$1 should be $4=$2 when testing $TESTSTRING.\n"
fi
}
check_all_charge_currents () {
for device in $MASTER $SLAVE; do
check_charging
print_results "$CHARGECUR" "$TESTVALUE10" "0"
done
}
set_loadbalancing () {
#make sure we switch lbl in the right order so we dont get modbus errors
if [ $loadbl_master -eq 0 ]; then
loadbl_slave=0
$CURLPOST $SLAVE/automated_testing?loadbl=$loadbl_slave
$CURLPOST $MASTER/automated_testing?loadbl=$loadbl_master
fi
if [ $loadbl_master -eq 1 ]; then
$CURLPOST $MASTER/automated_testing?loadbl=$loadbl_master
sleep 1
loadbl_slave=2
$CURLPOST $SLAVE/automated_testing?loadbl=$loadbl_slave
fi
}
MODESTR=("Off" "Normal" "Solar" "Smart")
set_mode () {
$CURLPOST $MASTER/settings?mode=$mode_master
if [ $loadbl_slave -eq 0 ]; then
$CURLPOST $SLAVE/settings?mode=$mode_master
fi
MODE=${MODESTR[$mode_master]}
printf "Testing LBL=$loadbl_master, mode=$MODE on $TESTSTRING.\r"
TESTVALUE10=$((TESTVALUE * 10))
}
overload_mains () {
# echo $TESTVALUE10 >feed_mains_$device
#now overload the mains by 1A
echo $(( TESTVALUE10 + 10 )) >feed_mains_$device
#settle switching modes AND stabilizing charging speeds
printf "Watch the charge current of device $device going down in 1-2A steps!\r"
sleep 10
#now stabilize the mains to MaxMains
echo $(( TESTVALUE10 )) >feed_mains_$device
}
set_mainsmeter_to_api () {
if [ ! -e "feed_mains_$device" ]; then
mkfifo feed_mains_$device
fi
if [ $device == $MASTER ]; then
MAC_ID=$MASTER_MAC_ID
else
MAC_ID=$SLAVE_MAC_ID
fi
./feed_mains.sh $MAC_ID <feed_mains_$device >/dev/null &
echo $TESTVALUE10 >feed_mains_$device
$CURLPOST $device/automated_testing?mainsmeter=9
}
run_test_loadbl0 () {
init_devices
init_currents
for device in $MASTER $SLAVE; do
set_mainsmeter_to_api
done
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
loadbl_master=0
set_loadbalancing
for mode_master in 3 2; do
set_mode
for device in $MASTER $SLAVE; do
$CURLPOST $device$CONFIG_COMMAND
overload_mains
check_charging
#we start charging at maxcurrent and then step down for approx. 1A per 670ms
print_results "$CHARGECUR" "${TARGET[$mode_master]}" "$MARGIN"
done
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
}
run_test_loadbl1 () {
init_devices
init_currents
device=$MASTER
set_mainsmeter_to_api
loadbl_master=1
set_loadbalancing
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
#if we are in loadbl 0 we don't test the slave device
for mode_master in 3 2; do
set_mode
$CURLPOST $device$CONFIG_COMMAND
overload_mains
TOTCUR=0
for device in $SLAVE $MASTER; do
check_charging
TOTCUR=$((TOTCUR + CHARGECUR))
done
#we started charging at maxcurrent and then stepped down for approx. 1A per 670ms
print_results "$TOTCUR" "${TARGET[$mode_master]}" "$MARGIN"
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
}
check_charging () {
#make sure we are actually charging
CURL=$(curl -s -X GET $device/settings)
STATE_ID=$(echo $CURL | jq ".evse.state_id")
print_results2 "$STATE_ID" "2" "0" "STATE_ID"
CHARGECUR=$(echo $CURL | jq ".settings.charge_current")
}
#TEST1: MODESWITCH TEST: test if mode changes on master reflects on slave and vice versa
NR=$((2**0))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="Modeswitch"
printf "Starting $TESTSTRING test #$NR:\n"
init_devices
$CURLPOST $MASTER/automated_testing?loadbl=1
$CURLPOST $SLAVE/automated_testing?loadbl=2
for mode_master in 1 2 3; do
$CURLPOST $MASTER/settings?mode=$mode_master
sleep 5
mode_slave=$(curl -s -X GET $SLAVE/settings | jq ".mode_id")
if [ "x"$mode_slave == "x"$mode_master ]; then
printf "$Green Passed $NC Master switching to mode $mode_master, slave follows.\n"
else
printf "$Red Failed $NC Master switching to mode $mode_master, slave is at $mode_slave.\n"
ABORT=1
fi
done
if [ $ABORT -ne 0 ]; then
exit $ABORT
fi
for mode_slave in 1 2 3; do
$CURLPOST $SLAVE/settings?mode=$mode_slave
sleep 5
mode_master=$(curl -s -X GET $MASTER/settings | jq ".mode_id")
if [ "x"$mode_slave == "x"$mode_master ]; then
printf "$Green Passed $NC Slave switching to $mode_slave, master follows.\n"
else
printf "$Red Failed $NC Slave switching to $mode_slave, master is at $mode_master.\n"
ABORT=1
fi
done
#if we cannot rely on correct switching of modes between master and slave, we will have to abort testing
if [ $ABORT -ne 0 ]; then
printf "Since one of the previous tests failed we abort testing."
exit $ABORT
fi
fi
#TEST2: SOCKET HARDWIRING TEST: test if Socket resistors in test bench limit our current // Configuration (0:Socket / 1:Fixed Cable)
# needs setting [MASTER|SLAVE]_SOCKET_HARDWIRED to the correct values of your test bench
NR=$((2**1))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="Socket Hardwiring"
printf "Starting $TESTSTRING test #$NR:\n"
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
init_devices
init_currents
#first load all settings before the test
for device in $SLAVE $MASTER; do
$CURLPOST $device/automated_testing?config=0
done
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
for loadbl_master in 0 1; do
set_loadbalancing
#if we are in loadbl 0 we test the slave device in loadbl 0 also
for mode_master in 1 2 3; do
set_mode
#settle switching modes AND stabilizing charging speeds
sleep 10
for device in $SLAVE $MASTER; do
check_charging
if [ $device == $MASTER ]; then
print_results "$CHARGECUR" "$MASTER_SOCKET_HARDWIRED" "0"
else
print_results "$CHARGECUR" "$SLAVE_SOCKET_HARDWIRED" "0"
fi
done
done
done
#for all other tests we don't want socket resistors to limit our currents, so switch to Fixed Cable
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?config=1
done
fi
#TEST4: MAXCURRENT TEST: test if MaxCurrent is obeyed
NR=$((2**2))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxCurrent"
printf "Starting $TESTSTRING test #$NR:\n"
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
init_devices
init_currents
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
for loadbl_master in 0 1; do
set_loadbalancing
#if we are in loadbl 0 we test the slave device in loadbl 0 also
TESTVALUE=12
for mode_master in 1 3 2; do
set_mode
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?current_max=$TESTVALUE
done
#settle switching modes AND stabilizing charging speeds
sleep 10
check_all_charge_currents
#increase testvalue to test if the device responds to that
TESTVALUE=$(( TESTVALUE + 1 ))
done
done
fi
#TEST8: MAXCIRCUIT TEST: test if MaxCircuit is obeyed
NR=$((2**3))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxCirCuit"
printf "Starting $TESTSTRING test #$NR:\n"
printf "Make sure your Sensorbox is on MAX power delivery to the grid, or Solar tests will fail!\n"
init_devices
init_currents
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
for loadbl_master in 0 1; do
set_loadbalancing
#if we are in loadbl 0 we test the slave device in loadbl 0 also
TESTVALUE=20
for mode_master in 1 3 2; do
set_mode
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?current_max_circuit=$TESTVALUE
done
#settle switching modes AND stabilizing charging speeds
sleep 13
if [ $loadbl_master -eq 0 ]; then
check_all_charge_currents
else
TOTCUR=0
for device in $SLAVE $MASTER; do
check_charging
TOTCUR=$((TOTCUR + CHARGECUR))
done
print_results "$TOTCUR" "$TESTVALUE10" "0"
fi
#increase testvalue to test if the device responds to that
TESTVALUE=$(( TESTVALUE + 1 ))
done
done
fi
#TEST16: MAXMAINS TEST: test if MaxMains is obeyed when using EM_API for loadbl=0
NR=$((2**4))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxMains via EM_API for loadbl=0"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
TESTVALUE=25
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
TARGET=(0 0 300 450)
CONFIG_COMMAND="/automated_testing?current_main=$TESTVALUE"
run_test_loadbl0
fi
#TEST32: MAXMAINS TEST: test if MaxMains is obeyed when using EM_API
NR=$((2**5))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxMains via EM_API for loadbl=1"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
TESTVALUE=25
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
TARGET=(0 0 420 560)
CONFIG_COMMAND="/automated_testing?current_main=$TESTVALUE"
run_test_loadbl1
fi
#TEST64: MAXSUMMAINS TEST: test if MaxSumMains is obeyed when using EM_API for loadbl=0
NR=$((2**6))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxSumMains via EM_API for loadbl=0"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
TESTVALUE=50
#Target values for Off, Normal, Solar, Smart mode RESPECTIVELY:
TARGET=(0 0 310 455)
CONFIG_COMMAND="/settings?current_max_sum_mains=$((TESTVALUE * 3))"
run_test_loadbl0
fi
#TEST128: MAXSUMMAINS TEST: test if MaxSumMains is obeyed when using EM_API for loadbl=1
NR=$((2**7))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="MaxSumMains via EM_API for loadbl=1"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
TESTVALUE=50
TARGET=(0 0 425 560)
CONFIG_COMMAND="/settings?current_max_sum_mains=$((TESTVALUE * 3))"
run_test_loadbl1
fi
#TEST256: STARTCURRENT TEST: test if StartCurrent is obeyed in Solar Mode for loadbl=0
NR=$((2**8))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=0"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
#make mains_overload feed mains_current with 3A to the grid
TESTVALUE=-3
#note that startcurrent shown as -4A on the display is stored as 4A !
#CONFIG_COMMAND="/settings?solar_start_current=4"
init_devices
init_currents
for device in $MASTER $SLAVE; do
set_mainsmeter_to_api
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
done
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
loadbl_master=0
set_loadbalancing
#SOLAR mode
mode_master=2
set_mode
for device in $MASTER $SLAVE; do
echo 60 >feed_mains_$device
done
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
sleep 50
for device in $MASTER $SLAVE; do
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
print_results2 "$TIMER" "28" "15" "SOLAR_STOP_TIMER"
done
TESTSTRING="Charging should stop after expiring SolarStopTimer"
printf "$TESTSTRING\r"
sleep 40
for device in $MASTER $SLAVE; do
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
print_results2 "$STATE_ID" "10" "0" "STATE_ID"
echo -20 >feed_mains_$device
done
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
printf "$TESTSTRING\r"
sleep 65
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
TESTSTRING="Feeding total of 18A should drop the charging current"
printf "$TESTSTRING\r"
for device in $MASTER $SLAVE; do
check_charging
#dropping the charge current by a few amps
echo 60 >feed_mains_$device
done
sleep 3
TESTSTRING="Feeding total of 15A should stabilize the charging current"
printf "$TESTSTRING\r"
for device in $MASTER $SLAVE; do
check_charging
print_results "$CHARGECUR" "475" "30"
echo 50 >feed_mains_$device
done
sleep 10
for device in $MASTER $SLAVE; do
check_charging
print_results "$CHARGECUR" "450" "35"
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
fi
#TEST512: STARTCURRENT TEST: test if StartCurrent is obeyed in Solar Mode for loadbl=1
NR=$((2**9))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
#make mains_overload feed mains_current with 3A to the grid
TESTVALUE=-3
#note that startcurrent shown as -4A on the display is stored as 4A !
#CONFIG_COMMAND="/settings?solar_start_current=4"
init_devices
init_currents
for device in $MASTER; do
set_mainsmeter_to_api
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
done
loadbl_master=1
set_loadbalancing
#SOLAR mode
sleep 2
mode_master=2
set_mode
sleep 2
printf "\n"
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
TESTSTRING="Feeding total of 3A so we should wait for the sun"
printf "$TESTSTRING\r"
echo 10 >feed_mains_$MASTER
sleep 5
for device in $MASTER $SLAVE; do
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
done
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
printf "$TESTSTRING\r"
echo -20 >feed_mains_$MASTER
sleep 70
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
sleep 2
for device in $MASTER $SLAVE; do
check_charging
done
TESTSTRING="Feeding total of 18A should drop the charging current"
printf "$TESTSTRING\r"
echo 60 >feed_mains_$MASTER
sleep 10
for device in $MASTER $SLAVE; do
check_charging
print_results "$CHARGECUR" "225" "20"
done
TESTSTRING="Feeding total of 15A should stabilize the charging current"
printf "$TESTSTRING\r"
echo 50 >feed_mains_$MASTER
sleep 10
for device in $MASTER $SLAVE; do
check_charging
print_results "$CHARGECUR" "210" "20"
done
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
echo 60 >feed_mains_$MASTER
sleep 60
for device in $MASTER $SLAVE; do
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
print_results2 "$TIMER" "15" "5" "SOLAR_STOP_TIMER"
done
TESTSTRING="Charging should stop after expiring SolarStopTimer"
printf "$TESTSTRING\r"
sleep 40
for device in $MASTER $SLAVE; do
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
done
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
printf "$TESTSTRING\r"
echo -20 >feed_mains_$MASTER
sleep 63
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
sleep 2
for device in $MASTER $SLAVE; do
check_charging
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
fi
#TEST1024: shortened version of test512
NR=$((2**10))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
TESTVALUE=-3
TESTVALUE10=$((TESTVALUE*10))
#note that startcurrent shown as -4A on the display is stored as 4A !
#CONFIG_COMMAND="/settings?solar_start_current=4"
init_devices
init_currents
for device in $MASTER; do
set_mainsmeter_to_api
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
done
#to speed up testing lower max_current
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?current_max=9
done
sleep 1
loadbl_master=1
set_loadbalancing
#SOLAR mode
sleep 2
mode_master=2
set_mode
sleep 2
printf "\n"
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
echo 60 >feed_mains_$MASTER
sleep 40
for device in $MASTER $SLAVE; do
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
print_results2 "$TIMER" "26" "5" "SOLAR_STOP_TIMER"
done
TESTSTRING="Charging should stop after expiring SolarStopTimer"
printf "$TESTSTRING\r"
sleep 40
for device in $MASTER $SLAVE; do
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
done
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
printf "$TESTSTRING\r"
echo -20 >feed_mains_$MASTER
sleep 63
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
sleep 2
for device in $MASTER $SLAVE; do
check_charging
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
fi
#TEST2048: modified version of test1024, only testing a master without any slaves
NR=$((2**11))
if [ $((SEL & NR)) -ne 0 ]; then
TESTSTRING="StartCurrent, StopTimer and ImportCurrent via EM_API for loadbl=1 with only Master"
printf "Starting $TESTSTRING test #$NR:\n"
#the margin for which we will accept the lowering/upping of the charge current, in dA
MARGIN=20
#make mains_overload feed mains_current with 3A per phase to the grid
TESTVALUE=-3
TESTVALUE10=$((TESTVALUE*10))
#note that startcurrent shown as -4A on the display is stored as 4A !
#CONFIG_COMMAND="/settings?solar_start_current=4"
init_devices
init_currents
for device in $MASTER; do
set_mainsmeter_to_api
$CURLPOST "$device/settings?solar_start_current=4&solar_max_import=15&solar_stop_time=1"
done
#to speed up testing lower max_current
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?current_max=9
done
loadbl_master=1
set_loadbalancing
#put slave into multi=disabled
$CURLPOST $SLAVE/automated_testing?loadbl=0
#SOLAR mode
sleep 2
mode_master=2
set_mode
sleep 2
printf "\n"
read -p "Make sure all EVSE's are set to CHARGING, then press <ENTER>" dummy
printf "Feeding total of 18A....chargecurrent should drop to 6A, then triggers stoptimer and when it expires, stops charging because over import limit of 15A\r"
TESTSTRING="SolarStopTimer should have been activated on overload on ImportCurrent"
echo 60 >feed_mains_$MASTER
sleep 65
for device in $MASTER; do
TIMER=$(curl -s -X GET $device/settings | jq ".evse.solar_stop_timer")
print_results2 "$TIMER" "8" "5" "SOLAR_STOP_TIMER"
done
TESTSTRING="Charging should stop after expiring SolarStopTimer"
printf "$TESTSTRING\r"
sleep 40
for device in $MASTER; do
STATE_ID=$(curl -s -X GET $device/settings | jq ".evse.state_id")
print_results2 "$STATE_ID" "9" "0" "STATE_ID"
done
TESTSTRING="Feeding total of -6A....should trigger ready-timer 60s"
printf "$TESTSTRING\r"
echo -20 >feed_mains_$MASTER
sleep 63
read -p "To start charging, set EVSE's to NO CHARGING and then to CHARGING again, then press <ENTER>" dummy
sleep 2
for device in $MASTER; do
check_charging
done
#set MainsMeter to Sensorbox
for device in $MASTER $SLAVE; do
$CURLPOST $device/automated_testing?mainsmeter=1
done
#kill all running subprocesses
pkill -P $$
fi
exit 0

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