diff --git a/.editorconfig b/.editorconfig
index 2fc657e..78cf7ff 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -14,6 +14,10 @@ indent_style = space
indent_size = 4
indent_style = space
+[*.{js}]
+indent_size = 4
+indent_style = tab
+
[*.{yml,yaml}]
indent_size = 2
indent_style = space
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 71d6dc0..5e23ed7 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -13,10 +13,10 @@ name: "CodeQL"
on:
push:
- branches: [ master ]
+ branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
- branches: [ master ]
+ branches: [ main ]
schedule:
- cron: '25 10 * * 6'
@@ -35,11 +35,17 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
+
+ - name: generate embedded resources
+ run: ls -la
+
+ - name: generate embedded resources
+ run: python build_script/create_embed.py
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v1
+ uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -47,10 +53,25 @@ jobs:
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
+ - uses: actions/cache@v3
+ with:
+ path: |
+ ~/.cache/pip
+ ~/.platformio/.cache
+ key: ${{ runner.os }}-pio
+ - uses: actions/setup-python@v4
+ with:
+ python-version: '3.9'
+ - name: Install PlatformIO Core
+ run: pip install --upgrade platformio
+
+ - name: Build PlatformIO Project
+ run: pio run
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- - name: Autobuild
- uses: github/codeql-action/autobuild@v1
+ # - name: Autobuild
+ # uses: github/codeql-action/autobuild@v2
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -64,4 +85,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ uses: github/codeql-action/analyze@v2
diff --git a/.gitignore b/.gitignore
index 7313e5a..f91f9bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,9 +9,6 @@
# embed is auto generated directory.
include/embed/**
-# temporary place files when develop web ui
-embed/static/**
-
_release
_release/**
diff --git a/build_script/create_embed.py b/build_script/create_embed.py
index b6488d3..65abe0f 100644
--- a/build_script/create_embed.py
+++ b/build_script/create_embed.py
@@ -12,7 +12,8 @@ def readall(path):
return data
-def create_name_from_filename(filename):
+def create_name_from_filename(path):
+ filename = os.path.basename(path)
ret = filename
ret = ret.replace(".", "_")
ret = ret.replace(" ", "_")
@@ -31,12 +32,6 @@ def create_name_from_filename(filename):
print(f"OUT_DIR = {OUT_DIR}")
print("=" * SEP_LENGTH)
-# access to global build environment
-#print(env.Dump())
-
-# access to project build environment (is used source files in "src" folder)
-#print(projenv.Dump())
-
#
# Script to build cpp file from embed directory
#
@@ -49,31 +44,33 @@ def create_name_from_filename(filename):
os.mkdir(OUT_DIR)
template = readall(TEMPLATE_FILE)
-for file in pathlib.Path(EMBED_DIR).iterdir():
- #print(file.name)
- if file.is_dir():
- print(f"ignored sub directory {file.name}")
- continue
+for root, dirs, files in os.walk(EMBED_DIR):
- if file.name.endswith(".md") or file.name.endswith(".sh"):
- print(f"ignored markdown file {file.name}")
- continue
+ for filename in files:
+ print(root, filename)
+ file = os.path.join(root, filename)
- # start generating source
- output = template
- data = readall(file)
+ if file.endswith(".md") or file.endswith(".sh"):
+ print(f"ignored markdown file {file.name}")
+ continue
- output_name = create_name_from_filename(file.name)
+ # start generating source
+ output = template
+ data = readall(file)
- # 変数名部分を置換。 変数名は全部大文字とする
- output = output.replace("$$REPLACE_NAME$$", output_name.upper()).replace("$$REPLACE_CONTENT$$", data)
- output_cpp_path = os.path.join(OUT_DIR, output_name + ".h")
+ output_name = create_name_from_filename(file)
- f = open(output_cpp_path, 'w')
- data = f.write(output)
- f.close()
+ # 変数名部分を置換。 変数名は全部大文字とする
+ output = output.replace("$$REPLACE_NAME$$", output_name.upper()).replace("$$REPLACE_CONTENT$$", data)
+ output_cpp_path = os.path.join(OUT_DIR, output_name + ".h")
+
+ # todo ファイル名重複チェック。すでにあったらコケる
+
+ f = open(output_cpp_path, 'w')
+ data = f.write(output)
+ f.close()
- print(f"generated {output_cpp_path}")
+ print(f"generated {output_cpp_path}")
print("=" * SEP_LENGTH)
diff --git a/create_release.sh b/create_release.sh
index 6bab4b6..7d961bc 100755
--- a/create_release.sh
+++ b/create_release.sh
@@ -1,10 +1,10 @@
#!/bin/bash -eu
MYDIR=$(cd "$(dirname "$0")"; pwd)
-RELEASE_BASE_DIR=${MYDIR}/_release/
-RELEASE_DIR=${RELEASE_BASE_DIR}/EnvBoyX
+RELEASE_BASE_DIR=${MYDIR}/_release
SRC_BUILD_DIR=${MYDIR}/.pio/build
-TGT_BUILD_DIR=${RELEASE_DIR}/.pio/build
+
+# SUBs
banner () {
echo ""
@@ -16,69 +16,76 @@ banner () {
copy_src_to_tgt () {
banner "Copying board build $1"
- # ESP32 dev board
- mkdir -p ${TGT_BUILD_DIR}/$1
- cp -v ${SRC_BUILD_DIR}/$1/*.bin ${TGT_BUILD_DIR}/$1/
+ # $1 = boardname
+ cp -v ${SRC_BUILD_DIR}/$1/firmware.bin ${RELEASE_BASE_DIR}/$1_EnvBoyX_$VER$VER_ADDITIONAL.bin
}
-banner "Delete source build dir and clean build"
-rm -rf ${MYDIR}/.pio
+# --------------------
+# MAIN
+# --------------------
cd ${MYDIR}
-pio run
-
-banner "Delete and create build directory"
-rm -rf ${RELEASE_BASE_DIR}
-
-mkdir -p ${RELEASE_DIR}
-
-cp ./platformio.ini ${RELEASE_DIR}/
-
-BOARDS=( esp32dev esp12e )
-for b in ${BOARDS[@]} ; do
- copy_src_to_tgt $b
-done
-
-banner "Add 'how to write' to build directory"
-cp ${MYDIR}/docs/how_to_write*.md ${RELEASE_DIR}
+# -------------------------------------------------------------------------
+banner "Get Version"
+# -------------------------------------------------------------------------
+MAJOR=$(grep " ver =" ./src/global.cpp | sed -r 's/.*"(.*+)".*/\1/')
+MINOR=$(grep " minorVer =" ./src/global.cpp | sed -r 's/.*"(.*+)".*/\1/')
+VER=$(echo "${MAJOR}.${MINOR}")
+echo "Version is ${VER}"
-banner "Creating Archive"
-
-rm -f ${MYDIR}/EnvBoyX*.tar.gz
+# -------------------------------------------------------------------------
+banner "Get Version additional info (debug, branch...)"
+# -------------------------------------------------------------------------
# git ブランチからファイル名判定
branch=`git symbolic-ref --short HEAD`
+if [ $branch != "main" ]; then
+ echo "git branch is not master/main!"
+ echo "Appending branch name"
+ VER_ADDITIONAL=$branch
+fi
+# DEBUGビルド判定
set +e
grep -i "DEBUG_BUILD.*TRUE" ${MYDIR}/src/global.cpp
IS_DEBUG=$?
+
+if [ $IS_DEBUG -eq 0 ] ; then
+ grep -i "const DEBUG_MODE.*true" ${MYDIR}/embed/static/config.js
+ IS_DEBUG=$?
+fi
set -e
if [ $IS_DEBUG -eq 0 ] ; then
echo "** DEBUG_BUILD IS SET TO TRUE"
- RELEASE_FILE_PATH=${MYDIR}/EnvBoyX-DEBUG.tar.gz
-elif [ $branch = "main" ]; then
- RELEASE_FILE_PATH=${MYDIR}/EnvBoyX.tar.gz
-else
- echo "git branch is not master/main!"
- echo "Appending branch name"
- RELEASE_FILE_PATH=${MYDIR}/EnvBoyX-$branch.tar.gz
+
+ if [ ${#VER_ADDITIONAL} -eq 0 ] ; then
+ VER_ADDITIONAL=DEBUG
+ else
+ VER_ADDITIONAL=$(echo "${VER_ADDITIONAL}-DEBUG")
+ fi
+fi
+
+if [ ${#VER_ADDITIONAL} -gt 0 ] ; then
+ VER_ADDITIONAL=$(echo "-$VER_ADDITIONAL")
fi
-rm -f ${MYDIR}/EnvBoyX*.tar.gz
-tar -C ${RELEASE_BASE_DIR} -zcvf ${RELEASE_FILE_PATH} .
+# -------------------------------------------------------------------------
+banner "Delete and create build directory"
+# -------------------------------------------------------------------------
+rm -rf ${RELEASE_BASE_DIR}
+mkdir -p ${RELEASE_BASE_DIR}
-banner "Release archive created ${RELEASE_FILE_PATH}"
+# -------------------------------------------------------------------------
+banner "Build"
+# -------------------------------------------------------------------------
-# Warning
+BOARDS=( esp32dev esp12e )
-echo "To upload, run:"
-echo "tar xvf `basename ${RELEASE_FILE_PATH}`"
-echo "cd `basename ${RELEASE_FILE_PATH}`"
-echo "pio run -t nobuild -t upload --disable-auto-clean"
-echo "If you want to specify board, use below."
-echo "pio run -e [esp32dev | esp12e] -t nobuild -t upload --disable-auto-clean"
+pio run --target clean
+pio run --environment esp32dev --environment esp12e
+
+for b in ${BOARDS[@]} ; do
+ copy_src_to_tgt $b
+done
-if [ $IS_DEBUG -eq 1 ] ; then
- banner "RELEASE VERSION ! Nice work !"
-fi
diff --git a/devel_writeback.sh b/devel_writeback.sh
deleted file mode 100755
index 417904b..0000000
--- a/devel_writeback.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-WORKDIR=$(dirname $0)
-
-cd $WORKDIR/embed
-
-watch -n 15 cp -v "./static/*" .
\ No newline at end of file
diff --git a/docs/api.md b/docs/api.md
index 5b02071..f3b53db 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -9,21 +9,26 @@ EnvBoyX has http web API.
| 2.0 | GET | / | JSON | sensor value as JSON.|
| 2.0 | GET | /ping | TEXT | returns pong. |
| 39.0 | GET | /stastics | JSON | stastics JSON |
-| 3.4 | GET | /brightness | JSON | value=0-255 set display brightness (0-255) 0 means OFF (adHoc, not config) |
-| 3.4 | GET | /display | JSON | set display power (1 = ON / 0 = OFF) |
| 40.0 | POST | /goto_setup | JSON | Go to setup mode at next boot |
-| 41.0 | POST | /mhz19b/abc | JSON | value=1 ON value=0 OFF |
-| 41.0 | POST | /mhz19b/zeroCalibration | TEXT | __DANGER__ Use if you know what you are doing |
-| 42.0 | GET | /config | JSON | Get config |
-| 42.0 | POST | /config | JSON | Change config |
-| 42.0 | POST | /config/commit | JSON | Save config |
-| 42.0 | POST | /config/revert | JSON | Revert to last saved config |
-| 43.0 | GET | /config/backup | TEXT | Get current running config on curl command line |
-| 44.0 | POST | /config/factory-reset | JSON | Delete ALL configs |
+| 3.4 | GET | /api/v1/brightness | JSON | value=0-255 set display brightness (0-255) 0 means OFF (adHoc, not config) |
+| 3.4 | GET | /api/v1/display | JSON | set display power (1 = ON / 0 = OFF) |
+| 41.0 | POST | /api/v1/mhz19b/abc | JSON | value=1 ON value=0 OFF |
+| 41.0 | POST | /api/v1/mhz19b/zeroCalibration | TEXT | __DANGER__ use if you know what you are doing. see below |
+| 42.0 | GET | /api/v1/config | JSON | Get config |
+| 42.0 | POST | /api/v1/config | JSON | Change config |
+| 42.0 | POST | /api/v1/config/commit | JSON | Save config |
+| 42.0 | POST | /api/v1/config/revert | JSON | Revert to last saved config |
+| 43.0 | GET | /api/v1/config/backup | TEXT | Get current running config on curl command line |
+| 44.0 | POST | /api/v1/config/factory-reset | JSON | Delete ALL configs |
NOTE: There is no reboot API, because of security reason.
-## /config API
+## /api/v1/mhz19b/zeroCalibration
+
+This method may break your MHZ19B accuracy.
+By datasheet, place mh-z19b in under 400ppm for at least 20 minutes.
+
+## /api/v1/config API
This API changes config (same thing in setup mode)
But some paramters are not changeable.
@@ -79,7 +84,7 @@ example: co2alerts.warning1.low
#### cURL example
```
-curl -s -X POST -d "displayFlip=yes&displayBrightness=50" "http://ebx32.local/config"
+curl -s -X POST -d "displayFlip=yes&displayBrightness=50" "http://ebx32.local/api/v1/config"
```
## HTTP Web API cURL examples
@@ -89,7 +94,8 @@ These are example of calling API
### Simple get API
```
-curl http://[envboy IP or mDNShostname.local]/
+curl http://[envboy IP or mDNShostname.local]/api/v1/getdata
+
{"product":"EnvBoyX","uptime":"01:18:02","uptimeMills":4682994,"temparature":"28.60","humidity":"35.00","pressure":"976.81","luminous":"16","luminousIr":"2","co2ppm":"-999","co2ppmAccuracy":"","rssi":-12}
```
@@ -106,3 +112,26 @@ OK
$ curl -X POST http://[envboy IP or mDNShostname.local]/goto_setup
OK
```
+
+### Appendix API urls until v45
+
+This information is old until v45.
+
+| since | METHOD | ENDPOINT | RETURN | description |
+| ------| ------ | ------------- | -------------------------- | -------|
+| 2.0 | GET | / | JSON | sensor value as JSON.|
+| 2.0 | GET | /ping | TEXT | returns pong. |
+| 39.0 | GET | /stastics | JSON | stastics JSON |
+| 3.4 | GET | /brightness | JSON | value=0-255 set display brightness (0-255) 0 means OFF (adHoc, not config) |
+| 3.4 | GET | /display | JSON | set display power (1 = ON / 0 = OFF) |
+| 40.0 | POST | /goto_setup | JSON | Go to setup mode at next boot |
+| 41.0 | POST | /mhz19b/abc | JSON | value=1 ON value=0 OFF |
+| 41.0 | POST | /mhz19b/zeroCalibration | TEXT | __DANGER__ Use if you know what you are doing |
+| 42.0 | GET | /config | JSON | Get config |
+| 42.0 | POST | /config | JSON | Change config |
+| 42.0 | POST | /config/commit | JSON | Save config |
+| 42.0 | POST | /config/revert | JSON | Revert to last saved config |
+| 43.0 | GET | /config/backup | TEXT | Get current running config on curl command line |
+| 44.0 | POST | /config/factory-reset | JSON | Delete ALL configs |
+
+NOTE: There is no reboot API, because of security reason.
diff --git a/docs/history.md b/docs/history.md
index bd237c3..eb7bcad 100644
--- a/docs/history.md
+++ b/docs/history.md
@@ -1,13 +1,28 @@
# Version History
-* FIX: Fix bug, or not friendly behavior
-* CHANGE: Change some behavior
-* ADD: Add new function
-* DROP: Delete some functions
-* NOTE: other things
+## v46.0: Big Usability improve update
+
+* Config WebUI is always ON (normal and setup mode)
+* Web Updater is added. (only on ESP32)
+
+### UPGRADE NOTE
+
+* Almost all API url are changed.
+* API URLs are prefixed by /api/v1 is added. (exception: /ping /goto_setup).
+* See [API Docs](api.md).
+
+### CHANGES
+
+* ADD: Web config both on normal mode and setup mode
+* BREAKING CHANGE: All API urls changed.
+* Deprecate: MQTT mode will be delete
## v45.0: Config update
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: AutoDimmer
* ADD: Config class (Internal mechanism) maybe consume 4KB memory.
* ADD: Config value validation (Setup web, Web API)
@@ -18,12 +33,12 @@
## v44.0: Internal refactoring Update
-### UPGRADE NOTE:
+### UPGRADE NOTE
* Some config are back to default value. (all alerts)
* If using before v42, update to v43 first. and get config backup using `http://[envboy]/config/backup` API
-### Changes
+### CHANGES
* CHANGE: Config version 12 -> 44 (New config version scheme. same as EBX version)
* ADD: MHZ-19B Auto Baseline Correction ON/OFF at boot time
@@ -37,6 +52,10 @@
## v43.0: Delta all update
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: Espressif 32 framework 3.0 -> 3.1
* ADD: Delta display
* FIX: Alert config can't save (warning1.high, caution2.low&high)
@@ -44,6 +63,10 @@
## v42.0: Config update
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: all API results are now JSON
* ADD: freeHeap to JSON, value of ESP.getFreeHeap() (update 15sec)
* ADD: Config GET / SET API
@@ -51,17 +74,29 @@
## v41.0: MH-Z19B update
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: API: MH-Z19B Auto Baseline Calibration ON/OFF
* ADD: API: MH-Z19B Zero Calibration
## v40.1: Bugfix release for v40
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: SSD1306: Missing unit when no alerts
* CHANGE: Add minor version
* CHANGE: Delete startup first screen
## v40: Pressure Delta update
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: CO2 ppm alert value is not good.
* ADD: Add POST /goto_setup API.
* FIX: Delete unused source code.
@@ -76,6 +111,10 @@
## v39: SH1106 Support release
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: CONFIG: Add SSD1306 / SH1106 switch
* CHANGE: HTTP: ESP32: Stop Async Web server. back to standard webserver to reduce code duplicate #42
* ADD: WiFi RSSI to JSON
@@ -83,6 +122,10 @@
## v38: Small update release
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: CONFIG: ESP32 now uses SPIFFS instead of LITTLEFS but no format or setup required (remove LITTLEFS to SPIFFS wrapper because of compile error)
* CHANGE: SSD1306: Move to U8G2 graphic library
* CHANGE: SSD1306: Lux unit "lx" to "Lx" (1 and l is very similer griph)
@@ -92,6 +135,10 @@
## v37: Alert update.
+### UPGRADE NOTE
+
+### CHANGES
+
* VERSION: 37. next version is v38.
* FIX: Alert settings are not saved on ESP32.
* FIX: Alert settings are not propery saved.
@@ -100,6 +147,10 @@
## v3.6: Bugfix release.
+### UPGRADE NOTE
+
+### CHANGES
+
* NOTE: LICENSE: EnvBoyX is now under APL 2.0 , Affected to all versions. (license terms are not shown before)
* FIX: TSL2561 can't enabled
* CHANGE: Serial speed changed to 74880. (was 115200)
@@ -108,11 +159,19 @@
## v3.5
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: Config: version 9 (was 8) and using JSON format
* ADD: Config: Migration between versions
## v3.4
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: Config: version 8 (was 6)
* FIX: SSD1306 not shown in Setup Mode
* ADD: Default Brightness setting
@@ -120,6 +179,10 @@
## v3.3
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: MH-Z19B wrong message
* FIX: Wrong uptime on JSON
* ADD: ST7789 Brightness change (via Web API)
@@ -128,6 +191,10 @@
## v3.2
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: Avoid using delay
* ADD: I2C scan on startup.
* FIX: ESP8266: I2C not working
@@ -135,16 +202,28 @@
## v3.1
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: vertical display mode(bigger font. ST7789 only)
* FIX: Refactoring
## v3.0
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: ST7789 Support (T-Display)
* NOTE: ST7789 is initial support, some screens are simplifyed.
## v2.7: Display item change update
+### UPGRADE NOTE
+
+### CHANGES
+
* CHANGE: Delete alive indicator "*" after EnvBoyX string.
* ADD: alive indicator. EnvBoyX's "X" character now blinks.
* CHANGE: prefix "IP:" before IP address
@@ -153,33 +232,63 @@
## v2.6
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: Fix mDNS not working
## v2.5
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: /display endpoint.
## v2.4
+### UPGRADE NOTE
+
+### CHANGES
+
* ADD: /brightness endpoint.
## v2.3
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: Unifing EnvBoyX (ESP8266) and EnvBoyX32 (ESP32) again.
## v2.2
+### UPGRADE NOTE
+
+### CHANGES
+
* missing version due to bug.
## v2.1
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: Split EnvBoyX (8266) and EnvBoyX32 (ESP32)
## v2.0
+### UPGRADE NOTE
+
+### CHANGES
+
* FIX: Move Arduino IDE to Platform.IO
## before v2.0
+Changelog for EnvboyX before 2.0 is below;
+
* https://github.com/yakumo-saki/envboy
* https://github.com/yakumo-saki/EnvBoyMQTT
diff --git a/docs/how_to_write-en.md b/docs/how_to_write-en.md
index 2df1de9..54844a1 100644
--- a/docs/how_to_write-en.md
+++ b/docs/how_to_write-en.md
@@ -27,3 +27,11 @@ pio run -t nobuild -t upload --disable-auto-clean
* `-t nobuild` no build
* `-t upload` Do write
* `--disable-auto-clean` Don't delete firmware.bin
+
+## Update via web browser
+
+This method only for ESP32 and EnvBoyX v46.0 or above.
+
+* download latest release from github.
+* Go to http://[envboyx ip address or hostname]/update
+* Upload and flash.
\ No newline at end of file
diff --git a/docs/how_to_write-jp.md b/docs/how_to_write-jp.md
index efaa7d0..560ad47 100644
--- a/docs/how_to_write-jp.md
+++ b/docs/how_to_write-jp.md
@@ -29,6 +29,14 @@ pio run -t nobuild -t upload --disable-auto-clean
* `-t upload` 書き込みする
* `--disable-auto-clean` ビルドディレクトリを自動的に削除しない(これをつけないと、ビルド済みバイナリが削除されます)
+## Update via web browser
+
+This method only for ESP32 and EnvBoyX v46.0 or above.
+
+* download latest release from github.
+* Go to http://[envboyx ip address or hostname]/update
+* Upload and flash.
+
## 蛇足
以下は、必要でなければ読む必要はありません。
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/embed/config.html b/embed/config.html
index 6db49e9..c1cee62 100644
--- a/embed/config.html
+++ b/embed/config.html
@@ -2,290 +2,305 @@
-
-
-
- EnvBoyX setting
-
-
+
+
+
+ EnvBoyX setting
+
+
- EnvBoyX Settings (EBXCFG.v45)
-
+
+
EnvBoyX Ver.00.0, Copyright 2018-2022 Yakumo Saki / ziomatrix.org.
\ No newline at end of file
diff --git a/embed/config.js b/embed/config.js
deleted file mode 100644
index 8acdbb6..0000000
--- a/embed/config.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const DEBUG_MODE = true;
-const DEBUG_API_HOST = "127.0.0.1";
-
-function loadConfig() {
-await fetch('http://10.1.0.130', {
- method: "GET"
- })
- .then(response => {
- if (response.ok) {
- return response.json();
- }
- // 404 や 500 ステータスならここに到達する
- throw new Error('Network response was not ok.');
- })
- .then(resJson => {
- console.log(JSON.stringify(resJson));
- })
- .catch(error => {
- // ネットワークエラーの場合はここに到達する
- console.error(error);
- })
-}
\ No newline at end of file
diff --git a/embed/static/config.js b/embed/static/config.js
new file mode 100644
index 0000000..f66c2d0
--- /dev/null
+++ b/embed/static/config.js
@@ -0,0 +1,375 @@
+"use strict";
+
+const DEBUG_MODE = false;
+const DEBUG_API_HOST = "10.1.0.110"; // デバッグ時、APIを投げる先
+
+const CONTENT_JSON = "application/json";
+const CONTENT_TEXT = "text/plain";
+const CONTENT_FORM = "application/x-www-form-urlencoded"
+const IGNORE_KEY = ["settingId"]
+
+let SETUP_MODE = false;
+
+// 画面ロード時のconfig。保存時に差分を取るために使用する。
+let LAST_CONFIG = null;
+
+function toPath(relativePath) {
+ if (!DEBUG_MODE) {
+ return relativePath;
+ }
+
+ var path = "http://" + DEBUG_API_HOST;
+ if (!relativePath.startsWith("/")) {
+ path = path + "/";
+ }
+
+ return path + relativePath;
+}
+
+async function httpGet(relativePath, contentType = CONTENT_JSON) {
+ if (DEBUG_MODE) {
+ console.log("httpGet " + toPath(relativePath));
+ }
+
+ const ret = await fetch(toPath(relativePath), {
+ method: "GET",
+ cache: "no-cache",
+ headers: {
+ "Content-Type": contentType,
+ },
+ });
+
+ if (!ret.ok) {
+ throw `httpGet: ${relativePath} response is not ok. ${ret.status} ${ret.statusText}`
+ }
+
+ return ret;
+}
+
+/**
+ *
+ * @param {string} relativePath
+ * @param {object} body
+ * @param {string} contentType CONTENT_*
+ * @returns promise
+ */
+async function httpPost(relativePath, body, contentType = CONTENT_TEXT) {
+ if (DEBUG_MODE) {
+ console.log("httpPost " + toPath(relativePath));
+ }
+
+ const ret = await fetch(toPath(relativePath), {
+ method: "POST",
+ cache: "no-cache",
+ headers: {
+ "Content-Type": contentType,
+ },
+ body: body
+ });
+
+ if (!ret.ok) {
+ throw `httpPost: ${relativePath} response is not ok. ${ret.status} ${ret.statusText}`
+ }
+
+ return ret;
+}
+
+function replaceVersion(replaceName, value) {
+ const elems = document.querySelectorAll(`span[replace='${replaceName}']`);
+ elems.forEach((element) => {
+ element.innerHTML = value;
+ });
+}
+
+/**
+ * ページロード時にEBXのバージョン等を置き換える
+ */
+async function setPageValues() {
+ const res = await httpGet("/ping");
+ console.log(res);
+
+ const json = await res.json();
+ console.log(json);
+
+ SETUP_MODE = json["mode"] == "SETUP";
+
+ replaceVersion("productVer", `ver.${json["majorVer"]}.${json["minorVer"]}`);
+ replaceVersion("settingId", json["settingId"]);
+}
+
+async function showSetupModeOnly() {
+ const elements = document.querySelectorAll(".setupModeOnly");
+ elements.forEach(element => {
+ element.hidden = !SETUP_MODE;
+ });
+
+}
+
+/**
+ * configMap の値をドキュメントにセットする
+ */
+function setConfigValuesToPage(configMap) {
+ configMap.forEach((v, k) => {
+
+ // console.log("key", k, "val", v);
+
+ const el = document.querySelector(`input[name="${k}"]`);
+ if (el == null) {
+ console.log(`key ${k} is not found on document.`);
+ return;
+ }
+
+ if (el.type === "radio") {
+ const radio = document.querySelector(
+ `input[name="${k}"][value="${v}"]`
+ );
+ if (radio == null) {
+ console.log(
+ `radio button name=${k} value=${v} is not found on document.`
+ );
+ }
+ radio.checked = true;
+ } else {
+ // input type=text,password,number
+ el.value = v;
+ }
+ });
+}
+
+/**
+ * configのキー、値をWeb上の要素にセット。checkboxには対応していない
+ * @param {string} key
+ * @returns boolean 成功 or 失敗
+ */
+function setInputValue(key, value) {
+
+ const els = document.querySelectorAll(`input[name='${key}']`);
+ if (els.length > 1) {
+ // RADIO
+ const elements = document.querySelectorAll(`input[name='${key}'][value='${value}']`);
+ if (elements.length > 1) {
+ console.log(`failed. multiple elements found ${key}=${value}`);
+ return false;
+ } else if (elements.length < 1) {
+ console.log(`failed. no elements found ${key}=${value}`);
+ return false;
+ }
+
+ elements[0].checked = true;
+ return;
+ } else if (els.length == 1) {
+ els[0].value = value;
+ return true;
+ } else if (els.length == 0) {
+ console.log(key, "element not found");
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Web上の要素から値を取得
+ * @param {string} key
+ * @returns string
+ */
+function getInputValue(key) {
+
+ const els = document.querySelectorAll(`input[name='${key}']`);
+ if (els.length > 1) {
+ // RADIO
+ const el = document.querySelector(`input[name='${key}']:checked`);
+ return el.value;
+ } else if (els.length == 1) {
+ return els[0].value;
+ } else if (els.length == 0) {
+ console.log(key, "element not found");
+ return null;
+ }
+
+ return "INVALID";
+}
+
+/**
+ * org -> new で異なっているものだけをMapにして返す
+ * @param {Map} orgMap
+ * @param {Map} newMap
+ * @return {Map}
+ */
+function createConfigDiff(orgMap, newMap) {
+ const ret = new Map();
+
+ orgMap.forEach((val, key) => {
+ const newVal = newMap.get(key);
+ // console.log("diff", key, val, newVal);
+ if (val !== newVal) {
+ ret.set(key, newVal);
+ }
+ });
+
+ return ret;
+}
+
+/**
+ * ConfigをEnvBoyに保存するAPIを呼ぶ
+ * @param {Map} configMap
+ * @return {object} result
+ */
+async function saveConfig(configMap) {
+ const params = new URLSearchParams()
+ configMap.forEach((v,k) => params.append(k, v));
+
+ try {
+ const res = await httpPost("/api/v1/config", params, CONTENT_FORM);
+ return res;
+ } catch (err) {
+ throw `Failed to send config: ${err}`;
+ }
+}
+
+async function commitRevertConfig(isCommit = true) {
+ const URL = "/api/v1/config/" + (isCommit ? "commit" : "revert");
+ try {
+ const commit = await httpPost(URL, "", CONTENT_JSON);
+ return commit;
+ } catch (err) {
+ throw `Failed to commit config: ${err}`;
+ }
+}
+
+async function commitConfig() {
+ return commitRevertConfig(true);
+}
+
+async function revertConfig() {
+ return commitRevertConfig(false);
+}
+
+
+/**
+ * 保存ボタンの処理
+ */
+async function saveConfigButton() {
+
+ const waitDialog = document.getElementById("waitDialog");
+
+ const newConfig = new Map();
+
+ // INPUTから取得
+ LAST_CONFIG.forEach((_, key) => {
+ const val = getInputValue(key);
+ newConfig.set(key, val);
+ });
+
+ console.log(newConfig);
+
+ // 差分作成
+ let configDiff = createConfigDiff(LAST_CONFIG, newConfig);
+
+ let confirmMessage = "変更を保存してよろしいですか?";
+ if (configDiff.size == 0) {
+ confirmMessage = confirmMessage + "\n\n※設定内容に変更がありません";
+ }
+
+ if (!window.confirm(confirmMessage)) {
+ return;
+ }
+
+ try {
+ waitDialog.showModal();
+
+ let needReboot = false;
+ if (configDiff.size > 0) {
+ const res = await saveConfig(configDiff);
+ const result = await res.json();
+ if (result.success != true) {
+ alert("設定内容にエラーがあります。設定は反映されていません。\n" + result.message + "\n"
+ + result.msgs.join("\n"));
+ return;
+ }
+ needReboot = result.needReboot;
+ }
+
+ const commit = await commitConfig();
+ const commitResult = await commit.json();
+ if (commitResult.success != true) {
+ alert("設定の保存に失敗しました。");
+ return;
+ }
+
+ if (needReboot) {
+ alert("設定を保存しました。\n再起動するまで反映されない設定があります。");
+ } else {
+ alert("設定を保存しました。");
+ }
+
+ } catch (err) {
+ console.log(err);
+ return;
+ } finally {
+ waitDialog.close();
+ }
+
+}
+
+/**
+ * configを取得してきたObjectからMapに変換する。
+ * ついでに不要な項目は捨てる
+ * @param {Object} configObj
+ * @return {Map}
+ */
+function configObjectToMap(configObj) {
+ const map = new Map();
+ Object.keys(configObj).forEach(k => {
+ if (IGNORE_KEY.includes(k)) {
+ return;
+ }
+ map.set(k, configObj[k]);
+ });
+ return map;
+}
+
+async function loadConfig() {
+ try {
+ const res = await httpGet("/api/v1/config", CONTENT_JSON);
+ const json = await res.json();
+ console.log(json);
+
+ if (!json["success"]) {
+ alert("エラーが発生しました。");
+ return;
+ }
+
+ const configObj = json["config"];
+ const confMap = configObjectToMap(configObj);
+
+ confMap.set("password", ""); // Add password as empty for later use
+ LAST_CONFIG = confMap;
+
+ setConfigValuesToPage(confMap);
+
+ } catch (err) {
+ alert(err);
+ return;
+ }
+
+}
+
+document.addEventListener("DOMContentLoaded", async (event) => {
+ const waitDialog = document.getElementById("waitDialog");
+ waitDialog.showModal();
+
+ console.log("DOM fully loaded and parsed");
+ document.getElementById("submit").addEventListener("click", async (event) => {
+ console.log("Submit Clicked");
+ await saveConfigButton();
+ });
+
+ await setPageValues();
+ await showSetupModeOnly();
+ await loadConfig();
+
+ waitDialog.close();
+});
+
diff --git a/embed/static/style.css b/embed/static/style.css
new file mode 100644
index 0000000..3867c6a
--- /dev/null
+++ b/embed/static/style.css
@@ -0,0 +1,45 @@
+@charset "utf-8";
+body {
+ background-color: aliceblue;
+ line-height: 110%;
+}
+
+body.setup_done {
+ background-color: paleturquoise;
+}
+
+body.setup_err {
+ background-color: lightsalmon;
+}
+
+span.header {
+ display: inline-block;
+ width: 6em;
+}
+
+input[type='text'],input[type='password'] {
+ width: 15em;
+}
+
+input.num {
+ width: 6em;
+}
+
+input#submit {
+ width: 200px;
+ height: 48px;
+}
+
+a.setup_again {
+ font-size: 150%;
+}
+
+dialog::backdrop {
+ background: rgba(0, 0, 0, 0.6);
+}
+
+.notice {
+ background-color: blanchedalmond;
+ border: 2px solid black;
+ padding: 0.5em 1.5em 0.5em 1.5em;
+}
\ No newline at end of file
diff --git a/embed/style.css b/embed/style.css
deleted file mode 100644
index d80f0e2..0000000
--- a/embed/style.css
+++ /dev/null
@@ -1,29 +0,0 @@
-@charset "utf-8";
-body {
- background-color: aliceblue;
-}
-
-body.setup_done {
- background-color: paleturquoise;
-}
-
-body.setup_err {
- background-color: lightsalmon;
-}
-
-input[type='text'] {
- width: 200px;
-}
-
-input.num {
- width: 50px;
-}
-
-input[type='submit'] {
- width: 200px;
- height: 48px;
-}
-
-a.setup_again {
- font-size: 150%;
-}
\ No newline at end of file
diff --git a/embed/update.html b/embed/update.html
new file mode 100644
index 0000000..f3977d2
--- /dev/null
+++ b/embed/update.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+ EnvBoyX updater
+
+
+
+
+
+ Firmware Update
+ This is beta feature. proceed with care !
+
+
+
\ No newline at end of file
diff --git a/embed/update_done.html b/embed/update_done.html
new file mode 100644
index 0000000..f81cc85
--- /dev/null
+++ b/embed/update_done.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ EnvBoyX update completed
+
+
+
+
+
+ Firmware Update completed.
+ EnvBoy is rebooting... please wait
+ NOTE: If not rebooting, reboot manually.
+
+
\ No newline at end of file
diff --git a/embed/update_fail.html b/embed/update_fail.html
new file mode 100644
index 0000000..ed9b8df
--- /dev/null
+++ b/embed/update_fail.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+ EnvBoyX update completed
+
+
+
+
+
+ Firmware Update failed.
+ Please reboot now.
+ But EnvBoy might be damaged.
+
+
\ No newline at end of file
diff --git a/embed/update_unsupport.html b/embed/update_unsupport.html
new file mode 100644
index 0000000..651d098
--- /dev/null
+++ b/embed/update_unsupport.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ EnvBoyX update
+
+
+
+
+
+ Firmware Update is not available
+ Your board is not support web updater
+
+
\ No newline at end of file
diff --git a/include/global.h b/include/global.h
index 5c0ab8e..e85c377 100644
--- a/include/global.h
+++ b/include/global.h
@@ -22,6 +22,11 @@ extern const String SETTING_ID;
extern const bool DEBUG_BUILD;
+// SETUPモード OR NORMALモード
+extern const int OPERATING_MODE_NORMAL;
+extern const int OPERATING_MODE_SETUP;
+extern int OPERATING_MODE;
+
// --------------------------------------------------------------------
// デバイス周りの定数
// --------------------------------------------------------------------
diff --git a/include/http_setup.h b/include/http_setup.h
index 9f94b2f..75b0751 100644
--- a/include/http_setup.h
+++ b/include/http_setup.h
@@ -1,19 +1,5 @@
#include
-/* 機種依存部分 */
-
-/**
- * SETUP GET /
- */
-void http_send_setup_post_root_html();
-
-/**
- * SETUP POST /
- */
-void http_send_setup_get_root_html();
-
-/* 以下は共通 */
-
/**
* 初期化
*/
diff --git a/include/network/api/api_util.h b/include/network/api/api_util.h
new file mode 100644
index 0000000..9fa75ce
--- /dev/null
+++ b/include/network/api/api_util.h
@@ -0,0 +1,11 @@
+#include
+#include
+#include
+
+bool parseBooleanString(const String value);
+std::vector stringSplit(String value, String delimiter);
+String jsonToString(DynamicJsonDocument& json);
+String http_normal_ping_json();
+
+// millisecond -> 00:00:00 形式の日付文字列を返す
+String getTimeString(unsigned long ms);
diff --git a/include/network/api/basic_api.h b/include/network/api/basic_api.h
new file mode 100644
index 0000000..0fb7eac
--- /dev/null
+++ b/include/network/api/basic_api.h
@@ -0,0 +1,2 @@
+
+void http_api_basic_setup();
\ No newline at end of file
diff --git a/include/network/http_api_config.h b/include/network/api/v1/config.h
similarity index 50%
rename from include/network/http_api_config.h
rename to include/network/api/v1/config.h
index 6047ba5..3786b90 100644
--- a/include/network/http_api_config.h
+++ b/include/network/api/v1/config.h
@@ -1,3 +1,2 @@
-#include "network/http_api.h"
void http_api_config_setup();
\ No newline at end of file
diff --git a/include/network/http_api_config_backup.h b/include/network/api/v1/config_backup.h
similarity index 100%
rename from include/network/http_api_config_backup.h
rename to include/network/api/v1/config_backup.h
diff --git a/include/network/http_api_config_getset.h b/include/network/api/v1/config_getset.h
similarity index 99%
rename from include/network/http_api_config_getset.h
rename to include/network/api/v1/config_getset.h
index 4eb1bfe..ef3272e 100644
--- a/include/network/http_api_config_getset.h
+++ b/include/network/api/v1/config_getset.h
@@ -1,5 +1,4 @@
#include
-
#include
// Config SET API のエントリポイント
diff --git a/include/network/http_api_display.h b/include/network/api/v1/display.h
similarity index 50%
rename from include/network/http_api_display.h
rename to include/network/api/v1/display.h
index f102c7a..6a84803 100644
--- a/include/network/http_api_display.h
+++ b/include/network/api/v1/display.h
@@ -1,3 +1,2 @@
-#include "network/http_api.h"
void http_api_display_setup();
\ No newline at end of file
diff --git a/include/network/api/v1/getdata.h b/include/network/api/v1/getdata.h
new file mode 100644
index 0000000..5481058
--- /dev/null
+++ b/include/network/api/v1/getdata.h
@@ -0,0 +1 @@
+void http_api_getdata_setup();
\ No newline at end of file
diff --git a/include/network/api/v1/mhz19b.h b/include/network/api/v1/mhz19b.h
new file mode 100644
index 0000000..7ec1681
--- /dev/null
+++ b/include/network/api/v1/mhz19b.h
@@ -0,0 +1,2 @@
+
+void http_api_mhz_setup();
\ No newline at end of file
diff --git a/include/network/goto_setup_api.h b/include/network/goto_setup_api.h
new file mode 100644
index 0000000..e556f7f
--- /dev/null
+++ b/include/network/goto_setup_api.h
@@ -0,0 +1 @@
+void http_api_gotosetup_setup();
\ No newline at end of file
diff --git a/include/network/http_api.h b/include/network/http_api.h
deleted file mode 100644
index 954fb91..0000000
--- a/include/network/http_api.h
+++ /dev/null
@@ -1,10 +0,0 @@
-
-#ifdef ESP32
-#include
-typedef WebServer HTTPWEBSERVER;
-#endif
-
-#ifdef ESP8266
-#include
-typedef ESP8266WebServer HTTPWEBSERVER;
-#endif
diff --git a/include/network/http_api_base.h b/include/network/http_api_base.h
deleted file mode 100644
index 11d17bc..0000000
--- a/include/network/http_api_base.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "network/http_api.h"
-
-void http_api_base_setup();
\ No newline at end of file
diff --git a/include/network/http_api_base_json.h b/include/network/http_api_base_json.h
deleted file mode 100644
index ae38513..0000000
--- a/include/network/http_api_base_json.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include
-
-String http_normal_not_found_html();
-
-String http_normal_data_json();
-
-String http_normal_ping_json();
diff --git a/include/network/http_api_mhz.h b/include/network/http_api_mhz.h
deleted file mode 100644
index 2e7ed7c..0000000
--- a/include/network/http_api_mhz.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include "network/http_api.h"
-
-void http_api_mhz_setup();
\ No newline at end of file
diff --git a/include/network/http_api_util.h b/include/network/http_api_util.h
deleted file mode 100644
index f4c1ae3..0000000
--- a/include/network/http_api_util.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#include
-
-bool parseBooleanString(const String value);
-std::vector stringSplit(String value, String delimiter);
-String jsonToString(DynamicJsonDocument& json);
\ No newline at end of file
diff --git a/include/network/http_not_found.h b/include/network/http_not_found.h
new file mode 100644
index 0000000..ae89666
--- /dev/null
+++ b/include/network/http_not_found.h
@@ -0,0 +1,3 @@
+#include
+
+void http_not_found_setup();
\ No newline at end of file
diff --git a/include/network/http_utils.h b/include/network/http_utils.h
index 872c605..98328b0 100644
--- a/include/network/http_utils.h
+++ b/include/network/http_utils.h
@@ -1,3 +1,5 @@
+#include
+
// HTTP ヘッダ (HTTP 1.1 〜) text/htmlで送信する
void sendHttpHeader();
@@ -10,3 +12,6 @@ void sendHtmlHeader();
// HTTP REDIRECTヘッダを送信する。これを実行したあとは何も送れない
void sendHttpRedirectHeader(String url);
+
+// CORS リクエストに応答する(http OPTIONS リクエスト)
+void http_handle_cors();
\ No newline at end of file
diff --git a/include/network/stastics_api.h b/include/network/stastics_api.h
new file mode 100644
index 0000000..f3c5916
--- /dev/null
+++ b/include/network/stastics_api.h
@@ -0,0 +1 @@
+void http_api_stastics_setup();
\ No newline at end of file
diff --git a/include/network/http_web_config.h b/include/network/web/http_web_config.h
similarity index 100%
rename from include/network/http_web_config.h
rename to include/network/web/http_web_config.h
diff --git a/include/network/web/http_web_updater.h b/include/network/web/http_web_updater.h
new file mode 100644
index 0000000..13f2fe1
--- /dev/null
+++ b/include/network/web/http_web_updater.h
@@ -0,0 +1,3 @@
+#include
+
+void http_web_updater_setup();
\ No newline at end of file
diff --git a/include/network/webserver.h b/include/network/webserver.h
index 4f30a57..cc5f16a 100644
--- a/include/network/webserver.h
+++ b/include/network/webserver.h
@@ -1,9 +1,11 @@
#ifdef ESP32
#include
extern WebServer server;
+typedef WebServer HTTPWEBSERVER;
#endif
#ifdef ESP8266
#include
extern ESP8266WebServer server;
+typedef ESP8266WebServer HTTPWEBSERVER;
#endif
diff --git a/platformio.ini b/platformio.ini
index ec29a89..08eef68 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -10,6 +10,7 @@
[platformio]
description = "EnvBoyX"
+default_envs = esp32dev
[env]
extra_scripts =
diff --git a/src/ConfigClass.h b/src/ConfigClass.h
index 1f5f9ec..b828ddb 100644
--- a/src/ConfigClass.h
+++ b/src/ConfigClass.h
@@ -30,10 +30,10 @@ enum class ConfigValueType {
// APIにより起動中に設定を変更する際の後処理を表す
enum class RunningConfigChangeFlags {
- OK = 0, // 反映された。
- REBOOT_REQ = 1, // 反映されたが、再起動するまで反映されない
- DISPLAY_REDRAW_REQ = 2, // 反映されたが、液晶を再描画する必要がある
- MDNS_RESTART_REQ = 3, // 反映されたが、mDNSを再起動する必要がある
+ OK = 0, // 後処理は不要
+ REBOOT_REQ = 1, // 再起動するまで反映されない
+ DISPLAY_REDRAW_REQ = 2, // 液晶を再描画する必要がある
+ MDNS_RESTART_REQ = 3, // mDNSを再起動する必要がある
BLOCKED = 4, // その設定は変更できない
};
diff --git a/src/ConfigClass_metadata.cpp b/src/ConfigClass_metadata.cpp
index 4e273d4..2a1cbd4 100644
--- a/src/ConfigClass_metadata.cpp
+++ b/src/ConfigClass_metadata.cpp
@@ -27,14 +27,14 @@ void Config::loadMetadata() {
ConfigMeta meta;
meta.key = ConfigNames::SSID;
meta.type = ConfigValueType::String;
- meta.flags = RunningConfigChangeFlags::BLOCKED;
+ meta.flags = RunningConfigChangeFlags::REBOOT_REQ; // v46 BLOCKED to REBOOT_REQ
this->addMeta(meta);
}
{
ConfigMeta meta;
meta.key = ConfigNames::PASSWORD;
meta.type = ConfigValueType::String;
- meta.flags = RunningConfigChangeFlags::BLOCKED;
+ meta.flags = RunningConfigChangeFlags::REBOOT_REQ; // v46 BLOCKED to REBOOT_REQ
this->addMeta(meta);
}
{
diff --git a/src/global.cpp b/src/global.cpp
index 8a26d27..7ae69c4 100644
--- a/src/global.cpp
+++ b/src/global.cpp
@@ -16,12 +16,13 @@ extern const String product_short = "EBX";
extern const bool DEBUG_BUILD = false;
// EnvBoyX
+// note: Also referenced by create_release.sh
extern const String product = "EnvBoyX";
-extern const String ver = "45"; // Major
+extern const String ver = "46"; // Major
extern const String minorVer = "0"; // Bugfix
extern const String ver_long = " Ver." + ver + "." + minorVer;
-// Setting version
+// Setting version (version number when settings changed)
extern const String SETTING_ID = "EBXCFG.v45";
// EnvBoyX Ver.53.0
@@ -63,3 +64,10 @@ Config *config;
// タイマー
// --------------------------------------------------------------------
TimerCall timer = TimerCall();
+
+// --------------------------------------------------------------------
+// 動作モード
+// --------------------------------------------------------------------
+extern const int OPERATING_MODE_NORMAL = 2;
+extern const int OPERATING_MODE_SETUP = 1;
+int OPERATING_MODE = 0;
diff --git a/src/main.cpp b/src/main.cpp
index 7e67f7f..7a25618 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,9 +38,12 @@ void setup()
isNormal = has_valid_config();
if (!isNormal) {
+ OPERATING_MODE = OPERATING_MODE_SETUP;
sectionlog(F("Entering setup mode."));
+
setup_setupmode();
} else {
+ OPERATING_MODE = OPERATING_MODE_NORMAL;
sectionlog(F("Entering normal mode."));
setup_normal();
diff --git a/src/network/api/http_api_util.cpp b/src/network/api/api_util.cpp
similarity index 68%
rename from src/network/api/http_api_util.cpp
rename to src/network/api/api_util.cpp
index bcf2440..053b283 100644
--- a/src/network/api/http_api_util.cpp
+++ b/src/network/api/api_util.cpp
@@ -4,6 +4,20 @@
#include "log.h"
+// millisecond -> 00:00:00 形式の日付文字列を返す
+String getTimeString(unsigned long ms) {
+ unsigned long second = ms / 1000;
+ unsigned long minute = second / 60;
+
+ int sec = second % 60;
+ int min = (second / 60) % 60;
+ int hr = minute / 60;
+
+ char buf[15];
+ snprintf (buf, sizeof buf,"%02d:%02d:%02d", hr, min, sec);
+ return String(buf);
+}
+
String jsonToString(DynamicJsonDocument& json) {
String jsonStr;
serializeJson(json, jsonStr);
diff --git a/src/network/api/basic_api.cpp b/src/network/api/basic_api.cpp
new file mode 100644
index 0000000..fb4e1d3
--- /dev/null
+++ b/src/network/api/basic_api.cpp
@@ -0,0 +1,60 @@
+#include
+#include
+
+#include "config.h"
+
+#include "log.h"
+#include "global.h"
+#include "display/display.h"
+
+#include "network/webserver.h"
+#include "network/api/basic_api.h"
+#include "network/api/api_util.h"
+#include "network/http_utils.h"
+
+extern HTTPWEBSERVER server;
+
+
+String http_normal_ping_json() {
+
+ unsigned long ms = millis();
+ String timeString = getTimeString(ms);
+
+ DynamicJsonDocument doc(2000);
+ doc["product"] = product;
+ doc["uptime"] = timeString;
+ doc["uptimeMills"] = ms;
+ doc["majorVer"] = ver;
+ doc["minorVer"] = minorVer;
+ doc["settingId"] = SETTING_ID;
+
+ if (OPERATING_MODE == OPERATING_MODE_NORMAL) {
+ doc["mode"] = "NORMAL";
+ } else if (OPERATING_MODE == OPERATING_MODE_SETUP) {
+ doc["mode"] = "SETUP";
+ } else {
+ doc["mode"] = "INVALID";
+ }
+
+ String json;
+ serializeJson(doc, json);
+
+ httplog(json);
+ return json;
+}
+
+void http_handle_ping() {
+ sendHttpHeader(MimeType::JSON);
+ String message = http_normal_ping_json();
+ server.sendContent(message);
+}
+
+void http_api_basic_setup() {
+ server.on ( "/ping", HTTP_GET, http_handle_ping);
+
+ // Config web ではPingが最初に実行されるので、ここにOPTION CORSの問い合わせが飛んでくる
+ // 一度答えればキャッシュされるようなので他のAPIには不要
+ server.on ( "/ping", HTTP_OPTIONS, http_handle_cors);
+
+ apilog("Basic API initialized.");
+}
\ No newline at end of file
diff --git a/src/network/api/goto_setup_api.cpp b/src/network/api/goto_setup_api.cpp
new file mode 100644
index 0000000..3d81c7a
--- /dev/null
+++ b/src/network/api/goto_setup_api.cpp
@@ -0,0 +1,35 @@
+#include
+#include
+
+#include "config.h"
+
+#include "log.h"
+#include "global.h"
+#include "display/display.h"
+
+#include "network/webserver.h"
+#include "network/api/basic_api.h"
+#include "network/api/api_util.h"
+#include "network/http_utils.h"
+
+extern HTTPWEBSERVER server;
+
+void http_handle_goto_setup() {
+
+ remove_configure_flag_file();
+
+ DynamicJsonDocument json(200);
+ json["command"] = "GOTO_SETUP";
+ json["success"] = true;
+ json["msg"] = "OK. Entering setup mode at next boot.";
+
+ String jsonStr;
+ serializeJson(json, jsonStr);
+ server.send(200, MimeType::JSON, jsonStr);
+}
+
+void http_api_gotosetup_setup() {
+ server.on ( "/goto_setup", HTTP_POST, http_handle_goto_setup );
+
+ apilog("Goto Setup API initialized.");
+}
\ No newline at end of file
diff --git a/src/network/api/http_api_base.cpp b/src/network/api/http_api_base.cpp
deleted file mode 100644
index bc29246..0000000
--- a/src/network/api/http_api_base.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include
-#include
-
-#include "config.h"
-
-#include "log.h"
-#include "global.h"
-#include "display/display.h"
-#include "network/http_api.h"
-#include "network/http_api_base_json.h"
-
-extern HTTPWEBSERVER server;
-
-void http_handle_data() {
- String message = http_normal_data_json();
- server.send(200, MimeType::JSON, message);
-}
-
-void http_handle_ping() {
- String message = http_normal_ping_json();
- server.send(200, MimeType::JSON, message);
-}
-
-void http_handle_stastics() {
- server.send(200, MimeType::JSON, stasticsJSON);
-}
-
-void http_handle_goto_setup() {
-
- remove_configure_flag_file();
-
- DynamicJsonDocument json(200);
- json["command"] = "GOTO_SETUP";
- json["success"] = true;
- json["msg"] = "OK. Entering setup mode at next boot.";
-
- String jsonStr;
- serializeJson(json, jsonStr);
- server.send(200, MimeType::JSON, jsonStr);
-}
-
-void http_handle_not_found() {
- String message = http_normal_not_found_html();
- server.send(404, MimeType::HTML, message);
-}
-
-void http_api_base_setup() {
- server.on ( "/ping", HTTP_GET, http_handle_ping);
- server.on ( "/", HTTP_GET, http_handle_data );
- server.on ( "/stastics", HTTP_GET, http_handle_stastics );
- server.on ( "/goto_setup", HTTP_POST, http_handle_goto_setup );
-
- server.onNotFound ( http_handle_not_found );
- apilog("API Base initialized.");
-}
\ No newline at end of file
diff --git a/src/network/api/stastics_api.cpp b/src/network/api/stastics_api.cpp
new file mode 100644
index 0000000..6cb4155
--- /dev/null
+++ b/src/network/api/stastics_api.cpp
@@ -0,0 +1,25 @@
+#include
+#include
+
+#include "config.h"
+
+#include "log.h"
+#include "global.h"
+#include "display/display.h"
+
+#include "network/webserver.h"
+#include "network/api/basic_api.h"
+#include "network/api/api_util.h"
+#include "network/http_utils.h"
+
+extern HTTPWEBSERVER server;
+
+void http_handle_stastics() {
+ server.send(200, MimeType::JSON, stasticsJSON);
+}
+
+void http_api_stastics_setup() {
+ server.on ( "/stastics", HTTP_GET, http_handle_stastics );
+
+ apilog("Stastics API initialized.");
+}
diff --git a/src/network/api/http_api_config.cpp b/src/network/api/v1/config.cpp
similarity index 51%
rename from src/network/api/http_api_config.cpp
rename to src/network/api/v1/config.cpp
index d7e8979..c09dd40 100644
--- a/src/network/api/http_api_config.cpp
+++ b/src/network/api/v1/config.cpp
@@ -4,38 +4,47 @@
#include "log.h"
#include "global.h"
#include "config.h"
-#include "network/http_api.h"
-#include "network/http_api_util.h"
-#include "network/http_api_config_getset.h"
-#include "network/http_api_config_backup.h"
#include "sensors/mhz19_uart.h"
+#include "network/webserver.h"
+#include "network/api/api_util.h"
+#include "network/api/v1/config_getset.h"
+#include "network/api/v1/config_backup.h"
+#include "network//http_utils.h"
+
extern HTTPWEBSERVER server;
void _get_config() {
+ sendHttpHeader(MimeType::JSON);
+
String keys = server.arg("key");
std::vector keyArray = stringSplit(keys, ",");
- DynamicJsonDocument json = create_config_json(keyArray);
+ DynamicJsonDocument json(1200);
json["command"] = "CONFIG_GET";
json["success"] = true;
+ json["config"] = create_config_json(keyArray);
String jsonStr;
serializeJson(json, jsonStr);
- server.send(200, MimeType::JSON, jsonStr);
+ server.sendContent(jsonStr);
}
void _set_config() {
+ sendHttpHeader(MimeType::JSON);
+
String jsonStr = updateConfig();
- server.send(200, MimeType::JSON, jsonStr);
+ server.sendContent(jsonStr);
}
void _revert_config() {
+ sendHttpHeader(MimeType::JSON);
+
// revertすると何が変更されるかわからないので、全ての反映を実行
reflectConfigAll();
@@ -46,27 +55,36 @@ void _revert_config() {
String jsonStr;
serializeJson(json, jsonStr);
- server.send(200, MimeType::JSON, jsonStr);
+ server.sendContent(jsonStr);
}
void _commit_config() {
+
DynamicJsonDocument json(100);
json["command"] = "CONFIG_COMMIT";
json["success"] = true;
save_config();
+ sendHttpHeader(MimeType::JSON);
+
String jsonStr;
serializeJson(json, jsonStr);
- server.send(200, MimeType::JSON, jsonStr);
+ server.sendContent(jsonStr);
}
void _backup_config() {
+
+ sendHttpHeader(MimeType::TEXT);
+
String ret = http_api_backup_config();
- server.send(200, MimeType::TEXT, ret);
+ server.sendContent(ret);
}
void _factory_reset() {
+
+ sendHttpHeader(MimeType::JSON);
+
DynamicJsonDocument json(8000);
apilog("FACTORY RESET INITIATED");
@@ -79,16 +97,21 @@ void _factory_reset() {
apilog("FACTORY RESET DONE");
- server.send(200, MimeType::JSON, jsonToString(json));
+ server.sendContent(jsonToString(json));
}
void http_api_config_setup() {
- server.on ( "/config", HTTP_GET, _get_config );
- server.on ( "/config", HTTP_POST, _set_config );
- server.on ( "/config/revert", HTTP_POST, _revert_config );
- server.on ( "/config/commit", HTTP_POST, _commit_config );
- server.on ( "/config/backup", HTTP_GET, _backup_config );
- server.on ( "/config/factory-reset", HTTP_POST, _factory_reset );
+ server.on ( "/api/v1/config", HTTP_GET, _get_config );
+ server.on ( "/api/v1/config", HTTP_POST, _set_config );
+ server.on ( "/api/v1/config/revert", HTTP_POST, _revert_config );
+ server.on ( "/api/v1/config/commit", HTTP_POST, _commit_config );
+ server.on ( "/api/v1/config/backup", HTTP_GET, _backup_config );
+ server.on ( "/api/v1/config/factory-reset", HTTP_POST, _factory_reset );
+ server.on ( "/api/v1/config", HTTP_OPTIONS, http_handle_cors);
+ server.on ( "/api/v1/config/revert", HTTP_POST, http_handle_cors );
+ server.on ( "/api/v1/config/commit", HTTP_OPTIONS, http_handle_cors );
+ server.on ( "/api/v1/config/backup", HTTP_OPTIONS, http_handle_cors );
+
apilog("API Config initialized.");
}
\ No newline at end of file
diff --git a/src/network/api/http_api_config_backup.cpp b/src/network/api/v1/config_backup.cpp
similarity index 85%
rename from src/network/api/http_api_config_backup.cpp
rename to src/network/api/v1/config_backup.cpp
index eb9f87e..ecbb076 100644
--- a/src/network/api/http_api_config_backup.cpp
+++ b/src/network/api/v1/config_backup.cpp
@@ -21,7 +21,7 @@ String http_api_backup_config() {
ret += keys;
ret += "\"";
- ret += " http://" + config->get(ConfigNames::MDNS) + ".local/config";
+ ret += " http://" + config->get(ConfigNames::MDNS) + ".local/api/v1/config";
return ret;
}
diff --git a/src/network/api/http_api_config_getset.cpp b/src/network/api/v1/config_getset.cpp
similarity index 94%
rename from src/network/api/http_api_config_getset.cpp
rename to src/network/api/v1/config_getset.cpp
index 6b96c18..53806fc 100644
--- a/src/network/api/http_api_config_getset.cpp
+++ b/src/network/api/v1/config_getset.cpp
@@ -10,8 +10,8 @@
#include "mdns_client.h"
-#include "network/http_api.h"
-#include "network/http_api_util.h"
+#include "network/webserver.h"
+#include "network/api/api_util.h"
#include "display/display.h"
extern unsigned int CONF_JSON_SIZE;
@@ -97,6 +97,7 @@ void _reflectConfig(ConfigHookFlags& flags, bool all = false) {
if (all || flags.needMDnsRestart) {
apilog("Exec mDNS restart.");
+ apilog("New mDNS name restart." + config->get(ConfigNames::MDNS));
mdns_hostname_change(config->get(ConfigNames::MDNS));
}
}
@@ -146,9 +147,9 @@ String updateConfig() {
json["msgs"] = msgs;
if (flags.configFailed) {
- json["message"] = "Some error detected. Check msg.";
+ json["message"] = "Some error detected. Check msgs.";
} else {
- json["message"] = "Don't forget calling /config/commit.";
+ json["message"] = "Don't forget calling config/commit. API";
}
json.shrinkToFit();
diff --git a/src/network/api/http_api_display.cpp b/src/network/api/v1/display.cpp
similarity index 84%
rename from src/network/api/http_api_display.cpp
rename to src/network/api/v1/display.cpp
index dbc4a1b..c279b5c 100644
--- a/src/network/api/http_api_display.cpp
+++ b/src/network/api/v1/display.cpp
@@ -4,7 +4,7 @@
#include "log.h"
#include "global.h"
#include "display/display.h"
-#include "network/http_api.h"
+#include "network/webserver.h"
extern HTTPWEBSERVER server;
@@ -43,8 +43,8 @@ void http_handle_brightness() {
}
void http_api_display_setup() {
- server.on ( "/brightness", HTTP_GET, http_handle_brightness );
- server.on ( "/display", HTTP_GET, http_handle_power );
+ server.on ( "/api/v1/brightness", HTTP_GET, http_handle_brightness );
+ server.on ( "/api/v1/display", HTTP_GET, http_handle_power );
apilog("API Display initialized.");
}
\ No newline at end of file
diff --git a/src/network/api/http_api_base_json.cpp b/src/network/api/v1/getdata.cpp
similarity index 55%
rename from src/network/api/http_api_base_json.cpp
rename to src/network/api/v1/getdata.cpp
index da54b8f..478a27a 100644
--- a/src/network/api/http_api_base_json.cpp
+++ b/src/network/api/v1/getdata.cpp
@@ -1,31 +1,21 @@
#include
#include
+#include "config.h"
+
#include "log.h"
#include "global.h"
+#include "display/display.h"
+#include "network/webserver.h"
+#include "network/api/api_util.h"
-String http_normal_not_found_html() {
- String message = "File Not Found\n\n";
- return message;
-}
-
-String get_time_string(unsigned long ms) {
- unsigned long second = ms / 1000;
- unsigned long minute = second / 60;
-
- int sec = second % 60;
- int min = (second / 60) % 60;
- int hr = minute / 60;
- char buf[15];
- snprintf (buf, sizeof buf,"%02d:%02d:%02d", hr, min, sec);
- return String(buf);
-}
+extern HTTPWEBSERVER server;
String http_normal_data_json() {
unsigned long ms = millis();
- String timeString = get_time_string(ms);
+ String timeString = getTimeString(ms);
char temp[10], hum[10], pres[10];
char lux[10], luxIr[10],ppm[10];
@@ -49,19 +39,13 @@ String http_normal_data_json() {
return json;
}
-String http_normal_ping_json() {
-
- unsigned long ms = millis();
- String timeString = get_time_string(ms);
-
- DynamicJsonDocument doc(2000);
- doc["product"] = product;
- doc["uptime"] = timeString;
- doc["uptimeMills"] = ms;
+void http_handle_data() {
+ String message = http_normal_data_json();
+ server.send(200, MimeType::JSON, message);
+}
- String json;
- serializeJson(doc, json);
+void http_api_getdata_setup() {
+ server.on ( "/api/v1/getdata", HTTP_GET, http_handle_data );
- httplog(json);
- return json;
-}
+ apilog("API getdata initialized.");
+}
\ No newline at end of file
diff --git a/src/network/api/http_api_mhz.cpp b/src/network/api/v1/mhz19b.cpp
similarity index 86%
rename from src/network/api/http_api_mhz.cpp
rename to src/network/api/v1/mhz19b.cpp
index 817f60b..1a37261 100644
--- a/src/network/api/http_api_mhz.cpp
+++ b/src/network/api/v1/mhz19b.cpp
@@ -3,8 +3,8 @@
#include "log.h"
#include "global.h"
-#include "network/http_api.h"
-#include "network/http_api_util.h"
+#include "network/webserver.h"
+#include "network/api/api_util.h"
#include "sensors/mhz19_uart.h"
extern HTTPWEBSERVER server;
@@ -72,9 +72,9 @@ void _mhz_zero_calibration() {
}
void http_api_mhz_setup() {
- server.on ( "/mhz19b/abc", HTTP_GET, _get_mhz_abc );
- server.on ( "/mhz19b/abc", HTTP_POST, _set_mhz_abc );
- server.on ( "/mhz19b/zeroCalibration", HTTP_POST, _mhz_zero_calibration );
+ server.on ( "/api/v1/mhz19b/abc", HTTP_GET, _get_mhz_abc );
+ server.on ( "/api/v1/mhz19b/abc", HTTP_POST, _set_mhz_abc );
+ server.on ( "/api/v1/mhz19b/zeroCalibration", HTTP_POST, _mhz_zero_calibration );
apilog("API MHZ-19B initialized.");
}
\ No newline at end of file
diff --git a/src/network/http_normal_web.cpp b/src/network/http_normal_web.cpp
index 5af786f..64f5748 100644
--- a/src/network/http_normal_web.cpp
+++ b/src/network/http_normal_web.cpp
@@ -7,25 +7,36 @@
#include "http_normal.h"
-#include "network/http_api.h"
-#include "network/http_api_base.h"
-#include "network/http_api_display.h"
-#include "network/http_api_mhz.h"
-#include "network/http_api_config.h"
-
-#include "network/http_web_config.h"
-
+#include "network/webserver.h"
+#include "network/http_not_found.h"
+#include "network/stastics_api.h"
+#include "network/goto_setup_api.h"
+#include "network/api/basic_api.h"
+#include "network/api/v1/display.h"
+#include "network/api/v1/mhz19b.h"
+#include "network/api/v1/config.h"
+#include "network/api/v1/getdata.h"
+
+#include "network/web/http_web_config.h"
+#include "network/web/http_web_updater.h"
extern HTTPWEBSERVER server;
void http_setup_normal() {
httplog("HTTP web server initializing");
+ http_not_found_setup();
+ http_api_gotosetup_setup();
+ http_api_stastics_setup();
+
+ http_api_basic_setup();
http_api_display_setup();
- http_api_base_setup();
+ http_api_getdata_setup();
http_api_mhz_setup();
http_api_config_setup();
+
http_web_config_setup();
+ http_web_updater_setup();
server.begin();
httplog("HTTP web server initialized");
diff --git a/src/network/http_not_found.cpp b/src/network/http_not_found.cpp
new file mode 100644
index 0000000..9f37064
--- /dev/null
+++ b/src/network/http_not_found.cpp
@@ -0,0 +1,29 @@
+#include
+#include
+
+#include "config.h"
+
+#include "global.h"
+
+#include "network/http_utils.h"
+#include "network/webserver.h"
+
+extern HTTPWEBSERVER server;
+
+void http_handle_not_found() {
+ // HEADER
+ server.sendContent("HTTP/1.1 404 FILE NOT FOUND\r\n");
+ server.sendContent("Content-Type: text/plain\r\n");
+ if (DEBUG_BUILD) {
+ server.sendContent("Access-Control-Allow-Origin: *\r\n");
+ }
+ server.sendContent("\r\n");
+
+ // CONTENT
+ String message = "404 File Not Found\n\n";
+ server.sendContent(message);
+}
+
+void http_not_found_setup() {
+ server.onNotFound ( http_handle_not_found );
+}
\ No newline at end of file
diff --git a/src/network/http_setup_web.cpp b/src/network/http_setup_web.cpp
index 4efce1c..c81c493 100644
--- a/src/network/http_setup_web.cpp
+++ b/src/network/http_setup_web.cpp
@@ -1,109 +1,36 @@
+
#include
#include "log.h"
#include "global.h"
#include "config.h"
-#include "http_setup.h"
-
-#include "halt.h"
-#include "utils.h"
-
-#include "embed/style_css.h"
+#include "http_normal.h"
#include "network/webserver.h"
-#include "network/http_utils.h"
-
-void http_setup_post_root_error_content(std::vector> errors) {
-
- sendHttpHeader();
- sendHtmlHeader();
-
- String html = "";
- html += "";
- html += "" + product + " Settings (" + SETTING_ID + ")
";
- html += "以下の設定値が正しくありません。
";
- html += "";
- for (auto& error: errors) {
- html += "- " + error.first + " = '" + error.second + "'
";
- }
- html += "
";
- html += "設定にエラーがあるため、保存できませんでした。
";
- html += "以下のリンクから再設定を行ってください。
";
- html += "
";
- html += "再設定";
- html += "";
- html += "