diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index dd84ea78..1cbff930 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -10,6 +10,11 @@ assignees: ''
**Describe the bug**
A clear and concise description of what the bug is.
+**Device information**
+- Screenshot of Zigbee and Device tab from root page of device
+- JSON object returned on [http://xzg.local/api?action=1¶m=all](http://xzg.local/api?action=1¶m=all)
+ *You **should** remove your credentials first*
+
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
@@ -23,16 +28,5 @@ A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
-**Desktop (please complete the following information):**
- - OS: [e.g. iOS]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
-
-**Smartphone (please complete the following information):**
- - Device: [e.g. iPhone6]
- - OS: [e.g. iOS8.1]
- - Browser [e.g. stock browser, safari]
- - Version [e.g. 22]
-
**Additional context**
Add any other context about the problem here.
diff --git a/.github/scripts/update_devices.py b/.github/scripts/update_devices.py
new file mode 100644
index 00000000..513c2857
--- /dev/null
+++ b/.github/scripts/update_devices.py
@@ -0,0 +1,129 @@
+import re
+
+def read_hw_file(hw_file_path):
+ with open(hw_file_path, 'r') as file:
+ return file.read()
+
+def parse_brd_configs(hw_content):
+ pattern = re.compile(r'BrdConfigStruct brdConfigs\[\] = \{(.*?)\};', re.DOTALL)
+ match = pattern.search(hw_content)
+ if match:
+ print("Found brdConfigs")
+ return match.group(1)
+ print("brdConfigs not found")
+ return ""
+
+def extract_devices(brd_configs, mist_configs):
+ devices = []
+ device_pattern = re.compile(r'\{\s*"([^"]+)",\s*\.ethConfigIndex = (-?\d+),\s*\.zbConfigIndex = -?\d+,\s*\.mistConfigIndex = (-?\d+)\s*\}', re.DOTALL)
+ for device_match in device_pattern.finditer(brd_configs):
+ device_name = device_match.group(1)
+ eth_config_index = int(device_match.group(2))
+ mist_config_index = int(device_match.group(3))
+
+ eth_is = eth_config_index > -1
+ btn_is = mist_configs[mist_config_index]['btnPin'] > -1
+ led_is = mist_configs[mist_config_index]['ledModePin'] > -1 or mist_configs[mist_config_index]['ledPwrPin'] > -1
+
+ device = {
+ 'name': device_name,
+ 'eth': ':white_check_mark:' if eth_is else ':x:',
+ 'button': ':white_check_mark:' if btn_is else ':x:',
+ 'led': ':white_check_mark:' if led_is else ':x:',
+ 'network_usb': ':white_check_mark:'
+ }
+ devices.append(device)
+ print(f"Extracted device: {device}")
+ return devices
+
+def parse_mist_configs(hw_content):
+ pattern = re.compile(r'MistConfig mistConfigs\[\] = \{(.*?)\};', re.DOTALL)
+ match = pattern.search(hw_content)
+ if match:
+ print("Found mistConfigs")
+ mist_configs = match.group(1)
+ return extract_mist_configs(mist_configs)
+ print("mistConfigs not found")
+ return []
+
+def extract_mist_configs(mist_configs):
+ configs = []
+ config_pattern = re.compile(r'\{\s*\.btnPin = (-?\d+),\s*\.btnPlr = \d+,\s*\.uartSelPin = -?\d+,\s*\.uartSelPlr = \d+,\s*\.ledModePin = (-?\d+),\s*\.ledModePlr = \d+,\s*\.ledPwrPin = (-?\d+),\s*\.ledPwrPlr = \d+\s*\}', re.DOTALL)
+ for config_match in config_pattern.finditer(mist_configs):
+ config = {
+ 'btnPin': int(config_match.group(1)),
+ 'ledModePin': int(config_match.group(2)),
+ 'ledPwrPin': int(config_match.group(3)),
+ }
+ configs.append(config)
+ print(f"Extracted mistConfig: {config}")
+ return configs
+
+def read_features_file(features_file_path):
+ with open(features_file_path, 'r') as file:
+ return file.read()
+
+def extract_existing_links(features_content):
+ device_links = {}
+ table_pattern = re.compile(r'\| \[(.*?)\]\((.*?)\)', re.DOTALL)
+ for match in table_pattern.finditer(features_content):
+ device_name = match.group(1)
+ link = match.group(2)
+ device_links[device_name] = link
+ print(f"Found link: {device_name} -> {link}")
+ return device_links
+
+def update_features_content(features_content, devices, device_links):
+ # Define the regular expression to match the whole Supported devices section
+ table_pattern = re.compile(r'(.*## 🎮 Supported devices)(\s+\| .+\|.+?)(\* Some devices do not support all features.*)', re.DOTALL)
+ match = table_pattern.search(features_content)
+ if match:
+
+ header = match.group(1)
+ footer = match.group(3)
+
+ updated_devices_table = "| Device Name | Button | ESP32 LEDs | Remote Network / USB mode selection | Ethernet |\n"
+ updated_devices_table += "| :---------------------------------------------------------- | :----------------: | :----------------: | :---------------------------------: | :----------------: |\n"
+
+ for device in devices:
+ device_name = device['name']
+ link = device_links.get(device_name, "")
+ if link:
+ device_name = f"[{device_name}]({link})"
+ device_row = f"| {device_name} | {device['button']} | {device['led']} | {device['network_usb']} | {device['eth']} |\n"
+ updated_devices_table += device_row
+
+ updated_features_content = header + "\n\n" + updated_devices_table + "\n" + footer
+ print("Updated features content")
+ return updated_features_content
+ print("Supported devices section not found")
+ return features_content
+
+def write_features_file(features_file_path, updated_content):
+ with open(features_file_path, 'w') as file:
+ file.write(updated_content)
+ print(f"Updated features file: {features_file_path}")
+
+def main():
+ hw_file_path = 'main_branch/src//const/hw.cpp'
+ features_file_path = 'mkdocs_branch/docs/features.md'
+
+ hw_content = read_hw_file(hw_file_path)
+ print(f"Read hw.cpp content: {len(hw_content)} characters")
+
+ brd_configs = parse_brd_configs(hw_content)
+ mist_configs = parse_mist_configs(hw_content)
+
+ devices = extract_devices(brd_configs, mist_configs)
+
+ features_content = read_features_file(features_file_path)
+ print(f"Read features.md content: {len(features_content)} characters")
+
+ device_links = extract_existing_links(features_content)
+
+ updated_content = update_features_content(features_content, devices, device_links)
+
+ write_features_file(features_file_path, updated_content)
+
+if __name__ == "__main__":
+ main()
diff --git a/.github/workflows/build_fw.yml b/.github/workflows/build_fw.yml
index 41e1e54e..681bfeea 100644
--- a/.github/workflows/build_fw.yml
+++ b/.github/workflows/build_fw.yml
@@ -17,6 +17,7 @@ jobs:
uses: actions/checkout@v3
with:
submodules: "recursive"
+ fetch-depth: 0
- name: Get Release tag
id: get_tag
@@ -53,7 +54,7 @@ jobs:
python-version: "3.9"
- name: Install PlatformIO Core
- run: pip install --upgrade platformio==6.1.11
+ run: pip install --upgrade platformio==6.1.15
- name: Build PlatformIO Project
run: pio run
@@ -97,6 +98,29 @@ jobs:
EOF
echo "Manifest file created."
+ - name: Get the latest commit SHA for the whole project
+ id: get_fw_commit_sha
+ run: echo "::set-output name=fw_commit_sha::$(git log -n 1 --pretty=format:%h)"
+
+ - name: Get the latest commit SHA in src/websrc
+ id: get_fs_commit_sha
+ run: echo "::set-output name=fs_commit_sha::$(git log -n 1 --pretty=format:%h -- src/websrc)"
+
+ - name: Create xzg.json for firmware update
+ run: |
+ cat << EOF > xzg.json
+ {
+ "name": "XZG Firmware",
+ "version": "${{ steps.get_tag.outputs.tag }}",
+ "fw_sha": "${{ steps.get_fw_commit_sha.outputs.fw_commit_sha }}",
+ "fs_sha": "${{ steps.get_fs_commit_sha.outputs.fs_commit_sha }}"
+ }
+ EOF
+ echo "xzg.json file created."
+
+ - name: Display xzg.json
+ run: cat xzg.json
+
- name: Release
uses: softprops/action-gh-release@v1
with:
@@ -106,6 +130,7 @@ jobs:
files: |
bin/XZG_${{ steps.get_tag.outputs.tag }}.ota.bin
bin/XZG_${{ steps.get_tag.outputs.tag }}.full.bin
+ bin/XZG_${{ steps.get_tag.outputs.tag }}.fs.bin
- name: Checkout releases branch
uses: actions/checkout@v3
@@ -120,14 +145,32 @@ jobs:
cp manifest.json releases/${{ steps.get_tag.outputs.tag }}/
echo "Files copied to releases directory."
+ - name: Prepare latest release directory
+ run: |
+ if [ -d releases/latest ]; then
+ rm -rf releases/latest
+ fi
+ mkdir -p releases/latest
+
+ - name: Copy file to latest release directory
+ run: |
+ cp xzg.json releases/latest/
+ # cp ./bin/XZG_${{ steps.get_tag.outputs.tag }}.ota.bin releases/latest/XZG.ota.bin
+ # cp ./bin/XZG_${{ steps.get_tag.outputs.tag }}.fs.bin releases/latest/XZG.fs.bin
+ echo "File copied to latest release directory."
+
- name: Commit and push files to releases branch
run: |
cd releases
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- git add .
- git commit -m "Add firmware and manifest for version ${{ steps.get_tag.outputs.tag }}"
- git push origin releases
+ if [[ -n $(git status --porcelain) ]]; then
+ git add .
+ git commit -m "${{ steps.get_tag.outputs.tag }}"
+ git push origin releases
+ else
+ echo "No changes to commit"
+ fi
- name: Send Telegram Notification about release
uses: appleboy/telegram-action@master
@@ -142,7 +185,7 @@ jobs:
- name: Send Discord Notification about release
run: |
+ json_payload=$(jq -n --arg content "https://github.com/${{ github.repository }}/releases/tag/${{ steps.get_tag.outputs.tag }}" '{content: $content}')
curl -H "Content-Type: application/json" \
- -d "{\"content\": \"${{ env.commitMessage }}\n\nhttps://github.com/${{ github.repository }}/releases/tag/${{ env.tag }}\"}" \
- ${{ secrets.DISCORD_WEBHOOK }}
-
+ -d "$json_payload" \
+ ${{ secrets.DISCORD_WEBHOOK }}
\ No newline at end of file
diff --git a/.github/workflows/build_wiki.yml b/.github/workflows/build_wiki.yml
new file mode 100644
index 00000000..8276f2f6
--- /dev/null
+++ b/.github/workflows/build_wiki.yml
@@ -0,0 +1,38 @@
+name: Build Wiki
+on:
+ workflow_dispatch:
+ workflow_run:
+ workflows: ["Update devices in wiki"]
+ types:
+ - completed
+ push:
+ branches:
+ - mkdocs
+
+permissions:
+ contents: write
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: mkdocs
+ - name: Configure Git Credentials
+ run: |
+ git config user.name github-actions[bot]
+ git config user.email 41898282+github-actions[bot]@users.noreply.github.com
+ - uses: actions/setup-python@v5
+ with:
+ python-version: 3.x
+ - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
+ - uses: actions/cache@v4
+ with:
+ key: mkdocs-material-${{ env.cache_id }}
+ path: .cache
+ restore-keys: |
+ mkdocs-material-
+ - run: pip install mkdocs-material
+ - run: pip install -r requirements.txt
+ - run: mkdocs gh-deploy --force
diff --git a/.github/workflows/update_devices.yml b/.github/workflows/update_devices.yml
new file mode 100644
index 00000000..f1455ba6
--- /dev/null
+++ b/.github/workflows/update_devices.yml
@@ -0,0 +1,56 @@
+name: Update devices in wiki
+
+permissions:
+ contents: write
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - src/const/hw.cpp
+
+jobs:
+ update-devices:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout main branch
+ uses: actions/checkout@v2
+ with:
+ ref: main
+ path: main_branch
+
+ - name: Checkout mkdocs branch
+ uses: actions/checkout@v2
+ with:
+ ref: mkdocs
+ path: mkdocs_branch
+
+ - name: Set up Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.x'
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+
+ - name: Run update_devices.py
+ run: python main_branch/.github/scripts/update_devices.py
+
+ - name: Commit and push changes
+ run: |
+ cd mkdocs_branch
+ git config --local user.email "action@github.com"
+ git config --local user.name "GitHub Action"
+ if [[ -n $(git status --porcelain) ]]; then
+ git add docs/features.md
+ git commit -m 'Update features.md with new device data'
+ git push origin mkdocs
+ else
+ echo "No changes to commit"
+ fi
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 873cc680..2033b33e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,8 @@ todo*
!lib
!platformio.ini
**/__pycache__
-tools/.no_web_update*
\ No newline at end of file
+tools/.no_web_update*
+managed_components
+old?
+data/*
+/tools/webfilesbuilder/.npm_install_marker*
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..7e97b898
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.16.0)
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(XZG)
+
diff --git a/README.md b/README.md
index db725fa9..ee7130b5 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# XZG Firmware
@@ -17,22 +17,6 @@ By focusing the community's efforts on enhancing one product, XZG aims to stream
thereby improving the capabilities and efficiency of your Zigbee Gateways. 🌍
-
-
## 🍓 Firmware features
@@ -52,8 +36,7 @@ Please follow the installation guide tailored to your hardware.
## 🛠️ Compiling from source
-### Local
-
+### VS Code
- You need npm and Python installed
- Install Visual Studio Code (VSC)
- Install PlatformIO extension to VSC
@@ -62,6 +45,23 @@ Please follow the installation guide tailored to your hardware.
- Open `XZG.code-workspace` in VSC
- Press "PlatformIO: Build" and wait until XZG*.bin are generated
+### Linux CLI
+- You need npm ad Python installed
+- Install PlatformIO Core (it's in many package managers)
+- Clone this repository
+ `git clone --recurse-submodules https://github.com/xyzroe/XZG.git`
+- Use `pio run` to build default environment
+- Binaries output to .pio/build/name_of_env/
+- Use `pio run -t upload` to build and upload
+ firmware image
+- Use `-e` flag to select a specific build:
+ `pio run -e env_name -t upload`
+
+### Language Server Setup
+- LSP (e.g. clangd and Neovim) users need to run
+ `pio run -t compiledb` to
+ generate a "compile_commands.json"
+
### Github
- Fork this repository;
- Made your changes;
@@ -93,11 +93,8 @@ Contributions are welcome! If you'd like to help improve the XZG Firmware, you c
Thanks to all the developers and contributors who make this project possible, and special thanks to [@mercenaruss](https://github.com/mercenaruss/) for **Zig Star devices development**.
-#### All projects contributors:
+#### All contributors:
-
-
-
Special thanks to all third-party library authors. Their work has significantly contributed to this project:
diff --git a/XZG.code-workspace b/XZG.code-workspace
index 206e598d..6cfeea7d 100644
--- a/XZG.code-workspace
+++ b/XZG.code-workspace
@@ -11,8 +11,17 @@
],
"cSpell.useGitignore": false,
"files.associations": {
- "*.tpp": "cpp"
+ "*.tpp": "cpp",
+ "typeinfo": "cpp",
+ "*.ipp": "cpp"
},
+ "i18n-ally.keysInUse": [
+ "p.lo.mlo",
+ "p.lo.mwc",
+ "p.lo.mnl",
+ "p.mq.disc.ph",
+ "p.mq.disc.n"
+ ],
},
"extensions": {
"recommendations": [
diff --git a/bin/.gitignore b/bin/.gitignore
index 625356ff..a0c907ca 100644
--- a/bin/.gitignore
+++ b/bin/.gitignore
@@ -1 +1,2 @@
-*debug*
\ No newline at end of file
+*debug*
+XZG*bin
\ No newline at end of file
diff --git a/dependencies.lock b/dependencies.lock
new file mode 100644
index 00000000..6efb4782
--- /dev/null
+++ b/dependencies.lock
@@ -0,0 +1,319 @@
+dependencies:
+ chmorgan/esp-libhelix-mp3:
+ component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.1.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.3
+ espressif/cbor:
+ component_hash: 440f4ee4504841cc9b4f3a8ef755776a612ac9dace355514c68b999868f990ff
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.3'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 0.6.0~1
+ espressif/esp-dsp:
+ component_hash: fa7fe74305df6da25867437ebcd4213e047cbfc0556cf92067ab657fce537c6e
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.2'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.5.2
+ espressif/esp-modbus:
+ component_hash: 2168e6b4cbda4d0281a2a2d1a40a3848e231473b2690d73217e3600fd2c98c12
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.3'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.16
+ espressif/esp-serial-flasher:
+ component_hash: dcc42a16712a1a636509cf0bf90e14032d7f2141784b533613b267b6aa318d52
+ dependencies: []
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 0.0.11
+ espressif/esp-zboss-lib:
+ component_hash: ceb89aaab088a3bc037c608bb7b7925e7116b0a7dda7c3476f44d9b06ff66c0a
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.5.0
+ espressif/esp-zigbee-lib:
+ component_hash: 238c29955025d3e4f430fd7243ad7f9f038b97775746032478f34532ad5979aa
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.5.0
+ espressif/esp_diag_data_store:
+ component_hash: 8849195251dbb8a2d7268335277cfa310cef36e4ac1e90cd59ad3be4269a30d7
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.1'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.1
+ espressif/esp_diagnostics:
+ component_hash: 2ea46a907cad1842e41a74b9efbd533ddd4908d3ccd06370c1f8355d41dd0342
+ dependencies:
+ - name: espressif/rmaker_common
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.4.0
+ - name: idf
+ require: private
+ version: '>=4.1'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.2.0
+ espressif/esp_insights:
+ component_hash: c2b5219b3343e79e6d62aa5589a204612416abe8bdb6ba11224dca1b9a3c62ba
+ dependencies:
+ - name: espressif/cbor
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >=5.0
+ version: ~0.6
+ - name: espressif/esp_diag_data_store
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.0
+ - name: espressif/esp_diagnostics
+ registry_url: https://components.espressif.com/
+ require: private
+ version: '>=1.2.0'
+ - name: espressif/rmaker_common
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.4.0
+ - name: idf
+ require: private
+ version: '>=4.1'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.2.0
+ espressif/esp_modem:
+ component_hash: e48da33fee082dd9d9a97a354a228057e07a14ac108766b40ad84e018205410a
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.1'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.1.0
+ espressif/esp_rainmaker:
+ component_hash: f89a4759347f3909417fb33059452f36c86befae9d10bda78b5417b7a5d19d11
+ dependencies:
+ - name: espressif/esp_rcp_update
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >= 5.1
+ version: ~1.2.0
+ - name: espressif/esp_schedule
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.2.0
+ - name: espressif/esp_secure_cert_mgr
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >=4.3
+ version: ^2.2.1
+ - name: espressif/json_generator
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.1.1
+ - name: espressif/json_parser
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.0.3
+ - name: espressif/mdns
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >=5.0
+ version: ^1.2.0
+ - name: espressif/network_provisioning
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >= 5.1
+ version: ~1.0.0
+ - name: espressif/rmaker_common
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.4.6
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.5.0
+ espressif/esp_rcp_update:
+ component_hash: c10afbd54a17f27eed880e61262b161656e6d36ad63376c307f9273e99d0abcd
+ dependencies:
+ - name: espressif/esp-serial-flasher
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~0.0.0
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.2.0
+ espressif/esp_schedule:
+ component_hash: e202a9c688f7f1ab601efb91d682e4bcfaebc508dcceee1a1e0a0d2d1ca75a26
+ dependencies:
+ - name: espressif/rmaker_common
+ registry_url: https://components.espressif.com/
+ require: private
+ version: ~1.4.2
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.2.0
+ espressif/esp_secure_cert_mgr:
+ component_hash: a20007d67e65a000670ab77e45d7554c943eb8dcb0abeada0a57dd9adac3a703
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.3'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 2.4.1
+ espressif/jsmn:
+ component_hash: d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.3'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.1.0
+ espressif/json_generator:
+ component_hash: 45033e1c199b13f1c8c1b544fb7d4e2df6a8e3071ebdcb1b22582b61a7974ff2
+ dependencies: []
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.1.2
+ espressif/json_parser:
+ component_hash: d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4
+ dependencies:
+ - name: espressif/jsmn
+ registry_url: https://components.espressif.com/
+ require: private
+ rules:
+ - if: idf_version >=5.0
+ version: ~1.1
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.3
+ espressif/libsodium:
+ component_hash: f6e982479a2389cb6868e8fb761cf23aba6c355a8090b3e906299807775f58a3
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.2'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.20~1
+ espressif/mdns:
+ component_hash: af6306fe65d637a3683d1cf671508fcedd6b05f9ca029a8815abeab64001fb8d
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.4.0
+ espressif/network_provisioning:
+ component_hash: ef2e10182fd1861e68b821491916327c25416ca7ae70e5a6e43313dbc71fe993
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.1'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.0.2
+ espressif/qrcode:
+ component_hash: 3b493771bc5d6ad30cbf87c25bf784aada8a08c941504355b55d6b75518ed7bc
+ dependencies: []
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 0.1.0~2
+ espressif/rmaker_common:
+ component_hash: a3a1df881278d0351fc850b77792fe8a196ddd6dcacbea203d606329cc6a0239
+ dependencies: []
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.4.6
+ idf:
+ source:
+ type: idf
+ version: 5.1.4
+ joltwallet/littlefs:
+ component_hash: 362f1f5beb5087b0c60169aff82676d2d0ffc991ead975212b0cba95959181c5
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=4.3'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.14.8
+direct_dependencies:
+- chmorgan/esp-libhelix-mp3
+- espressif/esp-dsp
+- espressif/esp-modbus
+- espressif/esp-zboss-lib
+- espressif/esp-zigbee-lib
+- espressif/esp_insights
+- espressif/esp_modem
+- espressif/esp_rainmaker
+- espressif/libsodium
+- espressif/mdns
+- espressif/network_provisioning
+- espressif/qrcode
+- espressif/rmaker_common
+- idf
+- joltwallet/littlefs
+manifest_hash: 6e90f5b15283407daa0c179aac46415cf48b3dd974c63431ebecfcee6f2c1510
+target: esp32
+version: 2.0.0
diff --git a/lib/CCTools/library.json b/lib/CCTools/library.json
index 38792b35..59339e3c 100644
--- a/lib/CCTools/library.json
+++ b/lib/CCTools/library.json
@@ -18,5 +18,5 @@
"type": "git",
"url": "https://github.com/xyzroe/CCTools"
},
- "version": "0.0.5"
+ "version": "0.0.6"
}
\ No newline at end of file
diff --git a/lib/CCTools/src/CCTools.cpp b/lib/CCTools/src/CCTools.cpp
index 8d125009..654a4312 100644
--- a/lib/CCTools/src/CCTools.cpp
+++ b/lib/CCTools/src/CCTools.cpp
@@ -60,17 +60,17 @@ bool CommandInterface::_wait_for_ack(unsigned long timeout = 1)
uint8_t received = _stream.read();
if (received == ACK_BYTE)
{
- // Serial.println("ACK received");
+ // DEBUG_PRINTLN("ACK received");
return true;
}
else if (received == NACK_BYTE)
{
- // Serial.println("NACK received");
+ // DEBUG_PRINTLN("NACK received");
return false;
}
}
}
- Serial.println("Timeout waiting for ACK/NACK");
+ DEBUG_PRINTLN("Timeout waiting for ACK/NACK");
return false;
}
@@ -119,7 +119,7 @@ uint32_t CommandInterface::_cmdGetChipId()
{
// 4 byte answ, the 2 LSB hold chip ID
byte *version = _receivePacket();
- // Serial.println("size " + String(sizeof(version)));
+ // DEBUG_PRINTLN("size " + String(sizeof(version)));
if (_checkLastCmd())
{
@@ -128,12 +128,12 @@ uint32_t CommandInterface::_cmdGetChipId()
value |= uint32_t(version[2]) << 8;
value |= uint32_t(version[1]) << 16;
value |= uint32_t(version[0]) << 24; // Most significant byte
- // Serial.print("ChipId ");
- // Serial.println(value, HEX);
+ // DEBUG_PRINT("ChipId ");
+ // DEBUG_PRINTLN(value, HEX);
if (sizeof(version) != 4)
{
- Serial.println("Unreasonable chip. Looks upper"); // repr(version) ?
+ DEBUG_PRINTLN("Unreasonable chip. Looks upper"); // repr(version) ?
return uint32_t(0);
}
@@ -160,7 +160,7 @@ byte *CommandInterface::_cmdGetStatus()
byte *stat = _receivePacket();
return stat;
}
- Serial.print("Error _cmdGetStatus");
+ DEBUG_PRINT("Error _cmdGetStatus");
return nullptr;
}
@@ -170,27 +170,28 @@ bool CommandInterface::_checkLastCmd()
byte *stat = _cmdGetStatus();
if (stat == nullptr)
{
- Serial.println("No response from target on status request.");
- Serial.println("(Did you disable the bootloader?)");
+ DEBUG_PRINTLN("No response from target on status request.");
+ DEBUG_PRINTLN("(Did you disable the bootloader?)");
return 0;
}
else
{
if (stat[0] == COMMAND_RET_SUCCESS)
{
- // Serial.println("Command Successful");
+ // DEBUG_PRINTLN("Command Successful");
return 1;
}
else
{
const char *stat_str = _getStatusString(stat[0]);
- if (stat_str == "Unknown")
+ //if (stat_str == "Unknown")
+ if (strcmp(stat_str, "Unknown") == 0)
{
- Serial.println("Warning: unrecognized status returned 0x" + String(stat[0]));
+ DEBUG_PRINTLN("Warning: unrecognized status returned 0x" + String(stat[0]));
}
else
{
- Serial.println("Target returned: 0x" + String(stat[0]) + " " + String(stat_str));
+ DEBUG_PRINTLN("Target returned: 0x" + String(stat[0]) + " " + String(stat_str));
}
return 0;
}
@@ -241,9 +242,9 @@ bool CommandInterface::_cmdDownload(uint32_t address, unsigned long size)
if (size % 4 != 0)
{
// If size is not a multiple of 4, handle the error
- Serial.print("Invalid data size: ");
- Serial.print(size);
- Serial.println(". Size must be a multiple of 4.");
+ DEBUG_PRINT("Invalid data size: ");
+ DEBUG_PRINT(size);
+ DEBUG_PRINTLN(". Size must be a multiple of 4.");
return false;
}
@@ -265,7 +266,7 @@ bool CommandInterface::_cmdDownload(uint32_t address, unsigned long size)
_stream.write(sizeBytes[2]); // # send size
_stream.write(sizeBytes[3]); // # send size
- // Serial.println("*** Mem Read (0x2A)");
+ // DEBUG_PRINTLN("*** Mem Read (0x2A)");
if (_wait_for_ack())
{
byte *data = _receivePacket();
@@ -285,9 +286,9 @@ bool CommandInterface::_cmdSendData(byte *data, unsigned int dataSize)
// Check if data size exceeds maximum limit
if (dataSize > maxDataSize)
{
- Serial.print("Data size too large: ");
- Serial.print(dataSize);
- Serial.println(". Maximum size allowed is 252 bytes.");
+ DEBUG_PRINT("Data size too large: ");
+ DEBUG_PRINT(dataSize);
+ DEBUG_PRINTLN(". Maximum size allowed is 252 bytes.");
return false;
}
@@ -310,7 +311,7 @@ bool CommandInterface::_cmdSendData(byte *data, unsigned int dataSize)
}
// Optionally print debug information to the serial monitor
- // Serial.println("*** Send Data (0x24)");
+ // DEBUG_PRINTLN("*** Send Data (0x24)");
// Assume _wait_for_ack() and _checkLastCmd() are implemented similarly to your previous method
if (_wait_for_ack())
@@ -348,7 +349,7 @@ byte *CommandInterface::_cmdMemRead(uint32_t address)
_stream.write(1); // # send width, 4 bytes
_stream.write(1); // # send number of reads
- // Serial.println("*** Mem Read (0x2A)");
+ // DEBUG_PRINTLN("*** Mem Read (0x2A)");
if (_wait_for_ack())
{
byte *data = _receivePacket();
@@ -379,10 +380,10 @@ byte *CommandInterface::_receivePacket()
return nullptr;
}
- // Debugging output, might use Serial.print in Arduino
- // Serial.print(F("*** received "));
- // Serial.print(size, HEX);
- // Serial.println(F(" bytes"));
+ // Debugging output, might use DEBUG_PRINT in Arduino
+ // DEBUG_PRINT(F("*** received "));
+ // DEBUG_PRINT(size, HEX);
+ // DEBUG_PRINTLN(F(" bytes"));
// Calculate checksum
byte calculatedChks = 0;
@@ -475,7 +476,7 @@ bool CommandInterface::_ledToggle(bool ledState)
bool CommandInterface::_nvram_osal_delete(uint16_t nvid)
{
// DEBUG_PRINT("Checking OsalNvIds ID: ");
- // Serial.print(nvid, HEX);
+ // DEBUG_PRINT(nvid, HEX);
// DEBUG_PRINT(" - ");
const uint8_t cmd1 = 0x21;
@@ -504,21 +505,21 @@ bool CommandInterface::_nvram_osal_delete(uint16_t nvid)
_stream.flush();
- // Serial.println("");
- // Serial.println("> " + String(cmd1, HEX) + " " + String(cmd2, HEX) + " " + String(lowByte, HEX) + " " + String(highByte, HEX) + " " + String(fcs, HEX));
+ // DEBUG_PRINTLN("");
+ // DEBUG_PRINTLN("> " + String(cmd1, HEX) + " " + String(cmd2, HEX) + " " + String(lowByte, HEX) + " " + String(highByte, HEX) + " " + String(fcs, HEX));
std::unique_ptr data(_receive_SRSP());
if (!data)
{
return false;
}
- // Serial.println("< " + String(data[0], HEX) + " " + String(data[1], HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX) + " " + String(data[4], HEX));
+ // DEBUG_PRINTLN("< " + String(data[0], HEX) + " " + String(data[1], HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX) + " " + String(data[4], HEX));
if (data[2] > 0 || data[3] > 0)
{
/*
DEBUG_PRINT("* Deleting OsalNvIds ID: ");
- Serial.print(nvid, HEX);
+ DEBUG_PRINT(nvid, HEX);
DEBUG_PRINT(" - ");
*/
@@ -547,15 +548,15 @@ bool CommandInterface::_nvram_osal_delete(uint16_t nvid)
_stream.flush();
- // Serial.println("");
- // Serial.println("> " + String(cmd1, HEX) + " " + String(cmd2, HEX) + " " + String(lowByte, HEX) + " " + String(highByte, HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX) + " " + String(fcs, HEX));
+ // DEBUG_PRINTLN("");
+ // DEBUG_PRINTLN("> " + String(cmd1, HEX) + " " + String(cmd2, HEX) + " " + String(lowByte, HEX) + " " + String(highByte, HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX) + " " + String(fcs, HEX));
std::unique_ptr data(_receive_SRSP());
if (!data)
{
return false;
}
- // Serial.println("< " + String(data[0], HEX) + " " + String(data[1], HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX));
+ // DEBUG_PRINTLN("< " + String(data[0], HEX) + " " + String(data[1], HEX) + " " + String(data[2], HEX) + " " + String(data[3], HEX));
}
return true;
}
@@ -565,9 +566,9 @@ bool CommandInterface::_nvram_ex_delete(uint16_t nvid, uint16_t subID)
/*
DEBUG_PRINT("Deleting ExNvIds sub ID: ");
- Serial.print(nvid, HEX);
+ DEBUG_PRINT(nvid, HEX);
DEBUG_PRINT(" ");
- Serial.print(subID, HEX);
+ DEBUG_PRINT(subID, HEX);
DEBUG_PRINT(" - ");
*/
const uint8_t cmd1 = 0x21;
@@ -611,7 +612,7 @@ bool CommandInterface::_nvram_ex_delete(uint16_t nvid, uint16_t subID)
{
return false;
}
- // Serial.println(String(data[2], HEX));
+ // DEBUG_PRINTLN(String(data[2], HEX));
if (data[2] == 0x0A)
{ // error
@@ -649,7 +650,7 @@ CommandInterface::zbInfoStruct CommandInterface::_checkFwVer()
chip.transportrev = zbVerBuf[0];
_cleanBuffer();
- DEBUG_PRINTLN("ZB v: " + String(chip.fwRev) + " Main: " + chip.maintrel + " Min: " + chip.minorrel + " Maj: " + chip.majorrel + " T: " + chip.transportrev + " P: " + chip.product);
+ // DEBUG_PRINTLN("ZB v: " + String(chip.fwRev) + " Main: " + chip.maintrel + " Min: " + chip.minorrel + " Maj: " + chip.majorrel + " T: " + chip.transportrev + " P: " + chip.product);
return chip;
}
@@ -735,10 +736,10 @@ bool CCTools::detectChipInfo()
uint32_t chip_id = _cmdGetChipId();
- // Serial.println(chip_id, HEX);
+ // DEBUG_PRINTLN(chip_id, HEX);
byte *device_id = _cmdMemRead(ICEPICK_DEVICE_ID);
- // Serial.println(sizeof(device_id));
+ // DEBUG_PRINTLN(sizeof(device_id));
uint32_t wafer_id = (((device_id[3] & 0x0F) << 16) +
(device_id[2] << 8) +
@@ -748,33 +749,33 @@ bool CCTools::detectChipInfo()
// We can now detect the exact device
- // Serial.print("wafer_id: ");
- // Serial.println(wafer_id, HEX);
- // Serial.print("pg_rev: ");
- // Serial.println(pg_rev, HEX);
+ // DEBUG_PRINT("wafer_id: ");
+ // DEBUG_PRINTLN(wafer_id, HEX);
+ // DEBUG_PRINT("pg_rev: ");
+ // DEBUG_PRINTLN(pg_rev, HEX);
byte *user_id = _cmdMemRead(FCFG_USER_ID);
- // Serial.println("Package: " + _getPackageString(user_id[2]));
+ // DEBUG_PRINTLN("Package: " + _getPackageString(user_id[2]));
byte protocols = user_id[1] >> 4;
- // Serial.print("protocols: ");
- // Serial.println(protocols, HEX);
+ // DEBUG_PRINT("protocols: ");
+ // DEBUG_PRINTLN(protocols, HEX);
byte *flash_size = _cmdMemRead(FLASH_SIZE);
- // Serial.print("flash_size: ");
- // Serial.println(flash_size[0], HEX);
+ // DEBUG_PRINT("flash_size: ");
+ // DEBUG_PRINTLN(flash_size[0], HEX);
// byte *ram_size = _cmdMemRead(PRCM_RAMHWOPT);
- // Serial.print("ram_size: ");
- // Serial.println(ram_size[0], HEX);
+ // DEBUG_PRINT("ram_size: ");
+ // DEBUG_PRINTLN(ram_size[0], HEX);
byte *ieee_b1 = _cmdMemRead(addr_ieee_address_primary + 4);
byte *ieee_b2 = _cmdMemRead(addr_ieee_address_primary);
if (ieee_b1 == nullptr || ieee_b2 == nullptr)
{
- Serial.println("Error read IEEE");
+ DEBUG_PRINTLN("Error read IEEE");
return false;
}
@@ -796,10 +797,11 @@ bool CCTools::detectChipInfo()
delete[] ieee_b2;
String chip_str;
- if (protocols & PROTO_MASK_IEEE == PROTO_MASK_IEEE)
+ //if (protocols & PROTO_MASK_IEEE == PROTO_MASK_IEEE)
+ if ((protocols & PROTO_MASK_IEEE) == PROTO_MASK_IEEE)
{
uint32_t test = 360372;
- // Serial.print(test, HEX);
+ // DEBUG_PRINT(test, HEX);
byte *b_val = _cmdMemRead(test);
chip.hwRev = _getChipDescription(chip_id, wafer_id, pg_rev, b_val[1]);
@@ -811,22 +813,16 @@ bool CCTools::detectChipInfo()
chip.flashSize = flash_size[0] * page_size;
test = chip.flashSize - 88 + 0xC;
- Serial.print(test, HEX);
+ //DEBUG_PRINT(test, HEX);
b_val = _cmdMemRead(test);
- Serial.print(" MODE_CONF: ");
- Serial.print(b_val[0], HEX);
- Serial.print(b_val[1], HEX);
- Serial.print(b_val[2], HEX);
- Serial.println(b_val[3], HEX);
+
+ chip.modeCfg = _decodeAddr(b_val[3], b_val[2], b_val[1], b_val[0]);
uint32_t bsl_adr = chip.flashSize - 88 + 0x30;
- Serial.print(bsl_adr, HEX);
+ //DEBUG_PRINT(bsl_adr, HEX);
byte *bsl_val = _cmdMemRead(bsl_adr);
- Serial.print(" bsl_val: ");
- Serial.print(bsl_val[0], HEX);
- Serial.print(bsl_val[1], HEX);
- Serial.print(bsl_val[2], HEX);
- Serial.println(bsl_val[3], HEX);
+
+ chip.bslCfg = _decodeAddr(bsl_val[3], bsl_val[2], bsl_val[1], bsl_val[0]);
return true;
}
@@ -874,6 +870,7 @@ bool CCTools::checkFirmwareVersion()
{
restart();
}
+ _cleanBuffer();
zbInfoStruct temp = _checkFwVer();
chip.fwRev = temp.fwRev;
chip.maintrel = temp.maintrel;
@@ -971,4 +968,9 @@ bool CCTools::nvram_reset(void (*logFunction)(const String&))
restart();
return success;
+}
+
+void CCTools::cleanBuffer()
+{
+ _cleanBuffer();
}
\ No newline at end of file
diff --git a/lib/CCTools/src/CCTools.h b/lib/CCTools/src/CCTools.h
index 0e139f7a..394f3de5 100644
--- a/lib/CCTools/src/CCTools.h
+++ b/lib/CCTools/src/CCTools.h
@@ -416,6 +416,8 @@ class CommandInterface
uint8_t majorrel;
uint8_t product;
uint8_t transportrev;
+ unsigned long modeCfg;
+ unsigned long bslCfg;
};
static const uint8_t ACK_BYTE = 0xCC;
@@ -614,6 +616,7 @@ class CCTools : public CommandInterface
bool checkFirmwareVersion();
bool ledToggle();
bool nvram_reset(void (*logFunction)(const String&));
+ void cleanBuffer();
};
#endif // CCTools_DETECT_H
\ No newline at end of file
diff --git a/partitions.csv b/partitions.csv
new file mode 100644
index 00000000..608eb781
--- /dev/null
+++ b/partitions.csv
@@ -0,0 +1,13 @@
+# Name, Type, SubType, Offset, Size, Flags
+nvs, data, nvs, 0x9000, 0x5000,
+# Раздел для хранения данных NVS (Non-Volatile Storage), 20 KB
+otadata, data, ota, 0xe000, 0x2000,
+# Раздел для хранения данных OTA (Over-the-Air) обновлений, 8 KB
+app0, app, ota_0, 0x10000, 0x180000,
+# Первый раздел для приложения, используемый для OTA обновлений, 1.5 MB (1572864 байт)
+app1, app, ota_1, 0x190000,0x180000,
+# Второй раздел для приложения, используемый для OTA обновлений, 1.5 MB (1572864 байт)
+eeprom, data, 0x99, 0x310000,0x1000,
+# Раздел для хранения данных EEPROM, 4 KB
+spiffs, data, spiffs, 0x311000,0xAF000,
+# Раздел для файловой системы SPIFFS, 704 KB (720896 байт)
\ No newline at end of file
diff --git a/partitions.default.csv b/partitions.default.csv
new file mode 100644
index 00000000..e1fd12be
--- /dev/null
+++ b/partitions.default.csv
@@ -0,0 +1,7 @@
+# Name, Type, SubType, Offset, Size, Flags ; Комментарии
+nvs, data, nvs, 0x9000, 0x5000, ; Раздел для хранения данных NVS (Non-Volatile Storage), 20 KB
+otadata, data, ota, 0xe000, 0x2000, ; Раздел для хранения данных OTA (Over-the-Air) обновлений, 8 KB
+app0, app, ota_0, 0x10000, 0x140000, ; Первый раздел для приложения, используемый для OTA обновлений, 1.25 MB (1310720 байт)
+app1, app, ota_1, 0x150000,0x140000, ; Второй раздел для приложения, используемый для OTA обновлений, 1.25 MB (1310720 байт)
+spiffs, data, spiffs, 0x290000,0x160000, ; Раздел для файловой системы SPIFFS, 1.5 MB (1441792 байт)
+coredump, data, coredump,0x3F0000,0x10000, ; Раздел для хранения дампов ядра, 64 KB (65536 байт)
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index a8e2fb53..cf6de6a7 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -8,88 +8,110 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
-;It was difficult to find working platform for https get function on solo board. Here are some logs:
-;https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5/platform-espressif32-2.0.5.zip ;- old build. - unkown board
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.01.00/platform-espressif32.zip ; fuck yeaar. it works on solo
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip ; fuck yeaar. it also works on solo
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.08.00/platform-espressif32.zip ; bitch. did't work -1
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.10.01/platform-espressif32.zip ;- build but -1
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip ;- last builds version but -1
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.10.05/platform-espressif32.zip ;- WiFiClientSecure.h: No such file or directory
-;https://github.com/tasmota/platform-espressif32/releases/download/2023.10.10/platform-espressif32.zip ; - logs2.txt
-;espressif32 @ ^6.4.0 ;- unkown board
-;espressif32 @ 5.1.0 ; - works but no solo
-
[platformio]
-default_envs = prod-solo
+default_envs = prod-dual
[env]
framework = arduino
lib_deps =
bblanchon/ArduinoJson@6.21.3
rlogiacco/CircularBuffer@>=1.4.0
- sstaub/Ticker@>=4.4.0
Martin-Laclaustra/CronAlarms
+ mathieucarbou/AsyncTCP@3.2.5
+ marvinroger/AsyncMqttClient@^0.9.0
+ robtillaart/DS18B20@^0.2.3
+
;husarnet/Husarnet ESP32 @ 1.2.0-5 ;husarnet example
- marvinroger/AsyncMqttClient @ ^0.9.0
- me-no-dev/AsyncTCP@1.1.1
+ ;husarnet/esp_husarnet^0.0.11
+ ;me-no-dev/AsyncTCP@1.1.1
+ ;elims/PsychicMqttClient@0.2.0
+ ;sstaub/Ticker@>=4.4.0
;plerup/EspSoftwareSerial@8.1.0
;marian-craciunescu/ESP32Ping@>=1.7
;me-no-dev/ESPAsyncWebServer@1.2.3
-monitor_filters = direct; log2file ; esp32_exception_decoder, default ;
+ ;milesburton/DallasTemperature @ ^3.11.0
+monitor_filters = direct, esp32_exception_decoder, log2file ; default ; ; ;
monitor_speed = 115200
upload_speed = 460800
;platform_packages =
; framework-arduinoespressif32 @ https://github.com/husarnet/arduino-esp32/releases/download/1.0.4-1/arduino-husarnet-esp32.zip ;husarnet example
+platform_packages =
+ tool-mklittlefs
+ ;framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/3.0.4.240826/framework-arduinoespressif32.zip
+ ;framework-arduinoespressif32-solo1 @ https://github.com/tasmota/arduino-esp32/releases/download/3.0.4.240826/framework-arduinoespressif32-solo1.zip
extra_scripts =
+ ;pre:tools/build/build_fs.py
pre:tools/build/pre_build.py
pre:tools/build/version_update.py
pre:tools/webfilesbuilder/build_html.py
+ pre:tools/export_compile_commands.py
post:tools/build/build.py
+
build_flags =
-DBUILD_ENV_NAME=$PIOENV
-
+ -Os
+
+[solo]
+platform = https://github.com/tasmota/platform-espressif32/releases/download/2024.09.10/platform-espressif32.zip ; Platform 2024.08.11 Tasmota Arduino Core 3.0.4 based on IDF 5.1.4+
+build_flags =
+ -DFRAMEWORK_ARDUINO_SOLO1
+ -DTASMOTA_PLATFORM
+
+[dual]
+platform = espressif32 @ 6.8.1
+;platform = espressif32@2.1.0 ;husarnet example
+
+[prod]
+build_flags =
+ -DCORE_DEBUG_LEVEL=0
+
+[debug]
+build_flags =
+ -DCORE_DEBUG_LEVEL=2
+ -DDEBUG
[env:prod-solo]
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip
+platform = ${solo.platform}
board = esp32-solo1
+board_build.filesystem = littlefs
build_flags =
${env.build_flags}
- -DFRAMEWORK_ARDUINO_SOLO1
+ ${solo.build_flags}
+ ${prod.build_flags}
board_build.f_cpu = 160000000L
extra_scripts =
${env.extra_scripts}
[env:debug-solo]
-platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.07.00/platform-espressif32.zip
+platform = ${solo.platform}
board = esp32-solo1
+board_build.filesystem = littlefs
build_flags =
- -DDEBUG
- ${env.build_flags}
- -DFRAMEWORK_ARDUINO_SOLO1
+ ${env.build_flags}
+ ${solo.build_flags}
+ ${debug.build_flags}
board_build.f_cpu = 160000000L
extra_scripts =
- ${env.extra_scripts}
-
+ ${env.extra_scripts}
+monitor_speed = 115200
-[env:prod]
-platform = espressif32 @ 6.4.0
+[env:prod-dual]
+platform = ${dual.platform}
board = esp32dev
+board_build.filesystem = littlefs
build_flags =
${env.build_flags}
+ ${prod.build_flags}
extra_scripts =
${env.extra_scripts}
-
-[env:debug]
-platform = espressif32 @ 6.6.0
-;platform = espressif32@2.1.0 ;husarnet example
+[env:debug-dual]
+platform = ${dual.platform}
board = esp32dev
+board_build.partitions = partitions.csv
+board_build.filesystem = littlefs
build_flags =
- -DDEBUG
${env.build_flags}
+ ${debug.build_flags}
extra_scripts =
- ${env.extra_scripts}
-lib_deps =
- ${env.lib_deps}
-
+ ${env.extra_scripts}
\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 00000000..483bc0cf
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+# 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})
diff --git a/src/config.cpp b/src/config.cpp
index 7d700abd..f5fef4db 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -23,8 +23,6 @@ extern struct NetworkConfigStruct networkCfg;
extern struct VpnConfigStruct vpnCfg;
extern struct MqttConfigStruct mqttCfg;
-String tag = "NVS";
-
void getNvsStats(int *total, int *used)
{
nvs_stats_t nvsStats;
@@ -75,7 +73,8 @@ String makeJsonConfig(const NetworkConfigStruct *networkCfg,
const VpnConfigStruct *vpnCfg,
const MqttConfigStruct *mqttCfg,
const SystemConfigStruct *systemCfg,
- const SysVarsStruct *systemVars)
+ const SysVarsStruct *systemVars,
+ const ThisConfigStruct *hwConfig)
{
StaticJsonDocument<2048> doc;
@@ -109,6 +108,12 @@ String makeJsonConfig(const NetworkConfigStruct *networkCfg,
serializeSysVarsToJson(*systemVars, varsJson);
}
+ if (hwConfig != nullptr)
+ {
+ JsonObject hw = doc.createNestedObject(hwConfigKey);
+ serializeHwConfigToJson(*hwConfig, hw);
+ }
+
String output;
serializeJsonPretty(doc, output);
return output;
@@ -127,6 +132,8 @@ void saveNetworkConfig(const NetworkConfigStruct &config)
preferences.putString(wifiGateKey, config.wifiGate.toString());
preferences.putString(wifiDns1Key, config.wifiDns1.toString());
preferences.putString(wifiDns2Key, config.wifiDns2.toString());
+ preferences.putInt(wifiPwrKey, static_cast(config.wifiPower));
+ preferences.putInt(wifiModeKey, config.wifiMode);
preferences.putBool(ethEnblKey, config.ethEnable);
preferences.putBool(ethDhcpKey, config.ethDhcp);
@@ -153,6 +160,9 @@ void loadNetworkConfig(NetworkConfigStruct &config)
config.wifiDns1.fromString(preferences.getString(wifiDns1Key, DNS_SERV_1));
config.wifiDns2.fromString(preferences.getString(wifiDns2Key, DNS_SERV_2));
+ config.wifiPower = static_cast(preferences.getInt(wifiPwrKey, WIFI_POWER_19_5dBm));
+ config.wifiMode = preferences.getInt(wifiModeKey, WIFI_PROTOCOL_11B);
+
config.ethEnable = preferences.getBool(ethEnblKey, true);
config.ethDhcp = preferences.getBool(ethDhcpKey, true);
config.ethIp.fromString(preferences.getString(ethIpKey));
@@ -216,6 +226,78 @@ void loadVpnConfig(VpnConfigStruct &config)
preferences.end();
}
+void saveHwConfig(const ThisConfigStruct &config)
+{
+ LOGD("saveHwConfig");
+ preferences.begin(hwConfigKey, false);
+ /*
+ char board[50];
+ EthConfig eth;
+ ZbConfig zb;
+ MistConfig mist;
+ */
+
+ preferences.putString(boardKey, config.board);
+ preferences.putInt(addrKey, config.eth.addr);
+ preferences.putInt(pwrPinKey, config.eth.pwrPin);
+ preferences.putInt(mdcPinKey, config.eth.mdcPin);
+ preferences.putInt(mdiPinKey, config.eth.mdiPin);
+ preferences.putInt(phyTypeKey, config.eth.phyType);
+ preferences.putInt(clkModeKey, config.eth.clkMode);
+ // preferences.putInt(pwrAltPinKey, config.eth.pwrAltPin);
+
+ preferences.putInt(zbTxPinKey, config.zb.txPin);
+ preferences.putInt(zbRxPinKey, config.zb.rxPin);
+ preferences.putInt(zbRstPinKey, config.zb.rstPin);
+ preferences.putInt(zbBslPinKey, config.zb.bslPin);
+
+ preferences.putInt(btnPinKey, config.mist.btnPin);
+ preferences.putInt(btnPlrKey, config.mist.btnPlr);
+ preferences.putInt(uartSelPinKey, config.mist.uartSelPin);
+ preferences.putInt(uartSelPlrKey, config.mist.uartSelPlr);
+ preferences.putInt(ledModePinKey, config.mist.ledModePin);
+ preferences.putInt(ledModePlrKey, config.mist.ledModePlr);
+ preferences.putInt(ledPwrPinKey, config.mist.ledPwrPin);
+ preferences.putInt(ledPwrPlrKey, config.mist.ledPwrPlr);
+
+ preferences.end();
+ LOGD("saveHwConfig end");
+}
+
+void loadHwConfig(ThisConfigStruct &config)
+{
+ preferences.begin(hwConfigKey, true);
+
+ strlcpy(config.board, preferences.getString(boardKey).c_str(), sizeof(config.board));
+
+ config.eth.addr = preferences.getInt(addrKey, 0);
+ config.eth.pwrPin = preferences.getInt(pwrPinKey, 0);
+ config.eth.mdcPin = preferences.getInt(mdcPinKey, -1);
+ config.eth.mdiPin = preferences.getInt(mdiPinKey, -1);
+ config.eth.phyType = static_cast(preferences.getInt(phyTypeKey, ETH_PHY_LAN8720));
+ config.eth.clkMode = static_cast(preferences.getInt(clkModeKey, ETH_CLOCK_GPIO0_IN));
+ // config.eth.pwrAltPin = preferences.getInt(pwrAltPinKey, -1);
+
+ config.zb.txPin = preferences.getInt(zbTxPinKey, -1);
+ config.zb.rxPin = preferences.getInt(zbRxPinKey, -1);
+ config.zb.rstPin = preferences.getInt(zbRstPinKey, -1);
+ config.zb.bslPin = preferences.getInt(zbBslPinKey, -1);
+
+ config.mist.btnPin = preferences.getInt(btnPinKey, -1);
+ config.mist.btnPlr = preferences.getInt(btnPlrKey, -1);
+ config.mist.uartSelPin = preferences.getInt(uartSelPinKey, -1);
+ config.mist.uartSelPlr = preferences.getInt(uartSelPlrKey, -1);
+ config.mist.ledModePin = preferences.getInt(ledModePinKey, -1);
+ config.mist.ledModePlr = preferences.getInt(ledModePlrKey, -1);
+ config.mist.ledPwrPin = preferences.getInt(ledPwrPinKey, -1);
+ config.mist.ledPwrPlr = preferences.getInt(ledPwrPlrKey, -1);
+
+ preferences.end();
+
+ String cfg = makeJsonConfig(NULL, NULL, NULL, NULL, NULL, &config);
+ LOGI("\n%s", cfg.c_str());
+}
+
void saveMqttConfig(const MqttConfigStruct &config)
{
preferences.begin(mqttConfigKey, false);
@@ -262,13 +344,14 @@ void saveSystemConfig(const SystemConfigStruct &config)
{
preferences.begin(systemConfigKey, false);
- preferences.putBool(keepWebKey, config.keepWeb);
+ // preferences.putBool(keepWebKey, config.keepWeb);
preferences.putBool(disableWebKey, config.disableWeb);
preferences.putBool(webAuthKey, config.webAuth);
preferences.putString(webUserKey, config.webUser);
preferences.putString(webPassKey, config.webPass);
preferences.putBool(fwEnabledKey, config.fwEnabled);
preferences.putString(fwIpKey, config.fwIp.toString());
+ preferences.putString(fwMaskKey, config.fwMask.toString());
preferences.putInt(serialSpeedKey, config.serialSpeed);
preferences.putInt(socketPortKey, config.socketPort);
preferences.putInt(tempOffsetKey, config.tempOffset);
@@ -285,6 +368,13 @@ void saveSystemConfig(const SystemConfigStruct &config)
// preferences.putInt(prevWorkModeKey, static_cast(config.prevWorkMode));
preferences.putInt(workModeKey, static_cast(config.workMode));
+ preferences.putInt(zbRoleKey, static_cast(config.zbRole));
+ preferences.putString(zbFwKey, config.zbFw);
+
+ preferences.putString(updCheckTimeKey, config.updCheckTime);
+ preferences.putString(updCheckDayKey, config.updCheckDay);
+ preferences.putBool(updAutoInstKey, config.updAutoInst);
+
preferences.end();
}
@@ -292,19 +382,20 @@ void loadSystemConfig(SystemConfigStruct &config)
{
preferences.begin(systemConfigKey, true);
- config.keepWeb = preferences.getBool(keepWebKey, true);
+ // config.keepWeb = preferences.getBool(keepWebKey, true);
config.disableWeb = preferences.getBool(disableWebKey, false);
config.webAuth = preferences.getBool(webAuthKey, false);
strlcpy(config.webUser, preferences.getString(webUserKey, "").c_str(), sizeof(config.webUser));
strlcpy(config.webPass, preferences.getString(webPassKey, "").c_str(), sizeof(config.webPass));
config.fwEnabled = preferences.getBool(fwEnabledKey, false);
config.fwIp.fromString(preferences.getString(fwIpKey, "0.0.0.0"));
+ config.fwMask.fromString(preferences.getString(fwMaskKey, "0.0.0.0"));
config.serialSpeed = preferences.getInt(serialSpeedKey, ZB_SERIAL_SPEED);
config.socketPort = preferences.getInt(socketPortKey, ZB_TCP_PORT);
config.tempOffset = preferences.getInt(tempOffsetKey, 0);
config.disableLedUSB = preferences.getBool(disableLedUSBKey, false);
config.disableLedPwr = preferences.getBool(disableLedPwrKey, false);
- config.refreshLogs = preferences.getInt(refreshLogsKey, 1);
+ config.refreshLogs = preferences.getInt(refreshLogsKey, 2);
strlcpy(config.hostname, preferences.getString(hostnameKey, "XZG").c_str(), sizeof(config.hostname)); /// to do add def host name!!
strlcpy(config.timeZone, preferences.getString(timeZoneKey, NTP_TIME_ZONE).c_str(), sizeof(config.timeZone));
strlcpy(config.ntpServ1, preferences.getString(ntpServ1Key, NTP_SERV_1).c_str(), sizeof(config.ntpServ1));
@@ -317,6 +408,13 @@ void loadSystemConfig(SystemConfigStruct &config)
// config.prevWorkMode = static_cast(preferences.getInt(prevWorkModeKey, WORK_MODE_NETWORK));
config.workMode = static_cast(preferences.getInt(workModeKey, WORK_MODE_NETWORK));
+ config.zbRole = static_cast(preferences.getInt(zbRoleKey, UNDEFINED));
+ strlcpy(config.zbFw, preferences.getString(zbFwKey, "?").c_str(), sizeof(config.zbFw));
+
+ strlcpy(config.updCheckTime, preferences.getString(updCheckTimeKey, UPD_CHK_TIME).c_str(), sizeof(config.updCheckTime));
+ strlcpy(config.updCheckDay, preferences.getString(updCheckDayKey, UPD_CHK_DAY).c_str(), sizeof(config.updCheckDay));
+ config.updAutoInst = preferences.getBool(updAutoInstKey, false);
+
preferences.end();
}
@@ -340,7 +438,6 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
{
const char *pageId = "pageId";
const char *on = "on";
- const char *contTypeText = "text/plain";
if (serverWeb.hasArg(pageId))
{
@@ -348,7 +445,7 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
{
case API_PAGE_GENERAL:
{
- if (serverWeb.hasArg(coordMode))
+ /*if (serverWeb.hasArg(coordMode))
{
const uint8_t mode = serverWeb.arg(coordMode).toInt();
if (mode <= 2 && mode >= 0)
@@ -360,7 +457,7 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
}
}
- configSys.keepWeb = serverWeb.hasArg(keepWebKey) == true;
+ configSys.keepWeb = serverWeb.hasArg(keepWebKey) == true;*/
configSys.disableLedPwr = serverWeb.hasArg(disableLedPwrKey) == true;
@@ -400,19 +497,33 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
if (serverWeb.hasArg(nmStartHourKey))
{
- LOGD("nmStartHourKey %s", String(serverWeb.arg(nmStartHourKey)));
+ // LOGD("nmStartHourKey %s", String(serverWeb.arg(nmStartHourKey)));
// Serial.println(convertTimeToCron(serverWeb.arg(nmStartHourKey)));
strncpy(configSys.nmStart, serverWeb.arg(nmStartHourKey).c_str(), sizeof(configSys.nmStart) - 1);
configSys.nmStart[sizeof(configSys.nmStart) - 1] = '\0'; // Guarantee a null terminator at the end
}
if (serverWeb.hasArg(nmEndHourKey))
{
- LOGD("nmEndHourKey %s", String(serverWeb.arg(nmEndHourKey)));
+ // LOGD("nmEndHourKey %s", String(serverWeb.arg(nmEndHourKey)));
// Serial.println(convertTimeToCron(serverWeb.arg(nmEndHourKey)));
strncpy(configSys.nmEnd, serverWeb.arg(nmEndHourKey).c_str(), sizeof(configSys.nmEnd) - 1);
configSys.nmEnd[sizeof(configSys.nmEnd) - 1] = '\0'; // Guarantee a null terminator at the end
}
+ if (serverWeb.hasArg(updCheckTimeKey))
+ {
+ strncpy(configSys.updCheckTime, serverWeb.arg(updCheckTimeKey).c_str(), sizeof(configSys.updCheckTime) - 1);
+ configSys.updCheckTime[sizeof(configSys.updCheckTime) - 1] = '\0'; // Guarantee a null terminator at the end
+ }
+
+ if (serverWeb.hasArg(updCheckDayKey))
+ {
+ strncpy(configSys.updCheckDay, serverWeb.arg(updCheckDayKey).c_str(), sizeof(configSys.updCheckDay) - 1);
+ configSys.updCheckDay[sizeof(configSys.updCheckDay) - 1] = '\0'; // Guarantee a null terminator at the end
+ }
+
+ configSys.updAutoInst = serverWeb.hasArg(updAutoInstKey) == true;
+
saveSystemConfig(configSys);
}
break;
@@ -451,6 +562,16 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
configNet.wifiDhcp = serverWeb.hasArg(wifiDhcpKey) == true;
+ if (serverWeb.hasArg(wifiModeKey))
+ {
+ configNet.wifiMode = serverWeb.arg(wifiModeKey).toInt();
+ }
+ if (serverWeb.hasArg(wifiPwrKey))
+ {
+ const uint8_t pwr = serverWeb.arg(wifiPwrKey).toInt();
+ configNet.wifiPower = static_cast(pwr);
+ }
+
if (serverWeb.arg(wifiSsidKey))
{
strncpy(configNet.wifiSsid, serverWeb.arg(wifiSsidKey).c_str(), sizeof(configNet.wifiSsid) - 1);
@@ -489,7 +610,7 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
}
saveNetworkConfig(configNet);
-
+ serverWeb.send(HTTP_CODE_OK, contTypeText, "ok");
if (configNet.wifiEnable)
{
WiFi.persistent(false);
@@ -507,13 +628,22 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
break;
case API_PAGE_ZIGBEE:
{
+ if (serverWeb.hasArg(coordMode))
+ {
+ const uint8_t mode = serverWeb.arg(coordMode).toInt();
+ if (mode <= 2 && mode >= 0)
+ {
+ configSys.workMode = static_cast(mode);
+ }
+ }
+
const char *baud = "baud";
if (serverWeb.hasArg(baud))
{
configSys.serialSpeed = serverWeb.arg(baud).toInt();
}
- if (serverWeb.hasArg(baud))
+ if (serverWeb.hasArg(portKey))
{
configSys.socketPort = serverWeb.arg(portKey).toInt();
}
@@ -527,15 +657,32 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
configSys.webAuth = serverWeb.hasArg(webAuthKey) == true;
+ const char *defaultCreds = "admin";
+ const char *defaultFwIp = "0.0.0.0";
+
if (serverWeb.hasArg(webUserKey))
{
- strncpy(configSys.webUser, serverWeb.arg(webUserKey).c_str(), sizeof(configSys.webUser) - 1);
+ if (serverWeb.arg(webUserKey).length() > 0)
+ {
+ strncpy(configSys.webUser, serverWeb.arg(webUserKey).c_str(), sizeof(configSys.webUser) - 1);
+ }
+ else
+ {
+ strncpy(configSys.webUser, defaultCreds, sizeof(configSys.webUser) - 1);
+ }
configSys.webUser[sizeof(configSys.webUser) - 1] = '\0'; // Guarantee a null terminator at the end
}
if (serverWeb.hasArg(webPassKey))
{
- strncpy(configSys.webPass, serverWeb.arg(webPassKey).c_str(), sizeof(configSys.webPass) - 1);
+ if (serverWeb.arg(webPassKey).length() > 0)
+ {
+ strncpy(configSys.webPass, serverWeb.arg(webPassKey).c_str(), sizeof(configSys.webPass) - 1);
+ }
+ else
+ {
+ strncpy(configSys.webPass, defaultCreds, sizeof(configSys.webPass) - 1);
+ }
configSys.webPass[sizeof(configSys.webPass) - 1] = '\0'; // Guarantee a null terminator at the end
}
@@ -543,7 +690,26 @@ void updateConfiguration(WebServer &serverWeb, SystemConfigStruct &configSys, Ne
if (serverWeb.hasArg(fwIpKey))
{
- configSys.fwIp.fromString(serverWeb.arg(fwIpKey));
+ if (serverWeb.arg(fwIpKey).length() > 0)
+ {
+ configSys.fwIp.fromString(serverWeb.arg(fwIpKey));
+ }
+ else
+ {
+ configSys.fwIp.fromString(defaultFwIp);
+ }
+ }
+
+ if (serverWeb.hasArg(fwMaskKey))
+ {
+ if (serverWeb.arg(fwMaskKey).length() > 0)
+ {
+ configSys.fwMask.fromString(serverWeb.arg(fwMaskKey));
+ }
+ else
+ {
+ configSys.fwMask.fromString(defaultFwIp);
+ }
}
saveSystemConfig(configSys);
@@ -702,6 +868,8 @@ void serializeNetworkConfigToJson(const NetworkConfigStruct &config, JsonObject
obj[wifiGateKey] = config.wifiGate.toString();
obj[wifiDns1Key] = config.wifiDns1.toString();
obj[wifiDns2Key] = config.wifiDns2.toString();
+ obj[wifiPwrKey] = config.wifiPower;
+ obj[wifiModeKey] = config.wifiMode;
obj[ethEnblKey] = config.ethEnable;
obj[ethDhcpKey] = config.ethDhcp;
obj[ethIpKey] = config.ethIp.toString();
@@ -754,13 +922,14 @@ void serializeMqttConfigToJson(const MqttConfigStruct &config, JsonObject obj)
// Serialization SystemConfigStruct into JSON
void serializeSystemConfigToJson(const SystemConfigStruct &config, JsonObject obj)
{
- obj[keepWebKey] = config.keepWeb;
+ // obj[keepWebKey] = config.keepWeb;
obj[disableWebKey] = config.disableWeb;
obj[webAuthKey] = config.webAuth;
obj[webUserKey] = config.webUser;
obj[webPassKey] = config.webPass;
obj[fwEnabledKey] = config.fwEnabled;
obj[fwIpKey] = config.fwIp.toString();
+ obj[fwMaskKey] = config.fwMask.toString();
obj[serialSpeedKey] = config.serialSpeed;
obj[socketPortKey] = config.socketPort;
obj[tempOffsetKey] = config.tempOffset;
@@ -776,6 +945,13 @@ void serializeSystemConfigToJson(const SystemConfigStruct &config, JsonObject ob
obj[nmEndHourKey] = config.nmEnd;
// obj[prevWorkModeKey] = static_cast(config.prevWorkMode);
obj[workModeKey] = static_cast(config.workMode);
+
+ obj[zbRoleKey] = static_cast(config.zbRole);
+ obj[zbFwKey] = config.zbFw;
+
+ obj[updCheckTimeKey] = config.updCheckTime;
+ obj[updCheckDayKey] = config.updCheckDay;
+ obj[updAutoInstKey] = config.updAutoInst;
}
// Serializing system variables to JSON
@@ -784,7 +960,7 @@ void serializeSysVarsToJson(const SysVarsStruct &vars, JsonObject obj)
obj[hwBtnIsKey] = vars.hwBtnIs;
obj[hwLedUsbIsKey] = vars.hwLedUsbIs;
obj[hwLedPwrIsKey] = vars.hwLedPwrIs;
- obj[hwUartSelIsKey] = vars.hwUartSelIs;
+ // obj[hwUartSelIsKey] = vars.hwUartSelIs;
obj[hwZigbeeIsKey] = vars.hwZigbeeIs;
obj[connectedClientsKey] = vars.connectedClients;
@@ -805,128 +981,181 @@ void serializeSysVarsToJson(const SysVarsStruct &vars, JsonObject obj)
obj[disableLedsKey] = vars.disableLeds;
// obj[zbLedStateKey] = vars.zbLedState;
- // obj[zbFlashingKey] = vars.zbFlashing;
+ obj[zbFlashingKey] = vars.zbFlashing;
obj[deviceIdKey] = vars.deviceId;
+
+ obj[espUpdAvailKey] = vars.updateEspAvail;
+ obj[rcpUpdAvailKey] = vars.updateZbAvail;
+}
+
+void serializeHwConfigToJson(const ThisConfigStruct &config, JsonObject obj)
+{
+ obj[boardKey] = config.board;
+ obj[addrKey] = config.eth.addr;
+ obj[pwrPinKey] = config.eth.pwrPin;
+ obj[mdcPinKey] = config.eth.mdcPin;
+ obj[mdiPinKey] = config.eth.mdiPin;
+ obj[phyTypeKey] = config.eth.phyType;
+ obj[clkModeKey] = config.eth.clkMode;
+ // obj[pwrAltPin] = config.eth.pwrAltPin;
+ obj[btnPinKey] = config.mist.btnPin;
+ obj[btnPlrKey] = config.mist.btnPlr;
+ obj[uartSelPinKey] = config.mist.uartSelPin;
+ obj[uartSelPlrKey] = config.mist.uartSelPlr;
+ obj[ledModePinKey] = config.mist.ledModePin;
+ obj[ledModePlrKey] = config.mist.ledModePlr;
+ obj[ledPwrPinKey] = config.mist.ledPwrPin;
+ obj[ledPwrPlrKey] = config.mist.ledPwrPlr;
+ obj[zbTxPinKey] = config.zb.txPin;
+ obj[zbRxPinKey] = config.zb.rxPin;
+ obj[zbRstPinKey] = config.zb.rstPin;
+ obj[zbBslPinKey] = config.zb.bslPin;
}
-bool loadFileConfigHW()
+bool loadFileConfigHW() // Support for old config HW files
{
- String tag = "HW";
- const char *board = "board";
- const char *addr = "addr";
- const char *pwrPin = "pwrPin";
- const char *mdcPin = "mdcPin";
- const char *mdiPin = "mdiPin";
- const char *phyType = "phyType";
- const char *clkMode = "clkMode";
- const char *pwrAltPin = "pwrAltPin";
- const char *btnPin = "btnPin";
- const char *btnPlr = "btnPlr";
- const char *uartSelPin = "uartSelPin";
- const char *uartSelPlr = "uartSelPlr";
- const char *ledModePin = "ledModePin";
- const char *ledModePlr = "ledModePlr";
- const char *ledPwrPin = "ledPwrPin";
- const char *ledPwrPlr = "ledPwrPlr";
- const char *zbTxPin = "zbTxPin";
- const char *zbRxPin = "zbRxPin";
- const char *zbRstPin = "zbRstPin";
- const char *zbBslPin = "zbBslPin";
File configFile = LittleFS.open(configFileHw, FILE_READ);
- if (!configFile)
+ /*if (!configFile)
{
+ if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED, "/lfs2", 10))
+ {
+ LOGD("Error with LITTLEFS");
+ }
DynamicJsonDocument config(300);
- config[board] = "";
+ config[boardKey] = "";
writeDefaultConfig(configFileHw, config);
configFile = LittleFS.open(configFileHw, FILE_READ);
- }
+ }*/
DynamicJsonDocument config(1024);
- deserializeJson(config, configFile);
- configFile.close();
-
- strlcpy(hwConfig.board, config[board] | "", sizeof(hwConfig.board));
- hwConfig.eth.addr = config[addr];
- hwConfig.eth.pwrPin = config[pwrPin];
- hwConfig.eth.mdcPin = config[mdcPin];
- hwConfig.eth.mdiPin = config[mdiPin];
- hwConfig.eth.phyType = config[phyType];
- hwConfig.eth.clkMode = config[clkMode];
- hwConfig.eth.pwrAltPin = config[pwrAltPin];
- hwConfig.mist.btnPin = config[btnPin];
- hwConfig.mist.btnPlr = config[btnPlr];
- hwConfig.mist.uartSelPin = config[uartSelPin];
- hwConfig.mist.uartSelPlr = config[uartSelPlr];
- hwConfig.mist.ledModePin = config[ledModePin];
- hwConfig.mist.ledModePlr = config[ledModePlr];
- hwConfig.mist.ledPwrPin = config[ledPwrPin];
- hwConfig.mist.ledPwrPlr = config[ledPwrPlr];
- hwConfig.zb.txPin = config[zbTxPin];
- hwConfig.zb.rxPin = config[zbRxPin];
- hwConfig.zb.rstPin = config[zbRstPin];
- hwConfig.zb.bslPin = config[zbBslPin];
-
- if (hwConfig.board[0] != '\0' && strlen(hwConfig.board) > 0)
+ if (configFile)
{
- LOGD("LOAD - OK");
- return true;
- }
- else
- {
- LOGI("LOAD - ERROR");
- int searchId = 0;
- if (config["searchId"])
+ deserializeJson(config, configFile);
+
+ configFile.close();
+
+ strlcpy(hwConfig.board, config[boardKey] | "", sizeof(hwConfig.board));
+ hwConfig.eth.addr = config[addrKey];
+ hwConfig.eth.pwrPin = config[pwrPinKey];
+ hwConfig.eth.mdcPin = config[mdcPinKey];
+ hwConfig.eth.mdiPin = config[mdiPinKey];
+ hwConfig.eth.phyType = config[phyTypeKey];
+ hwConfig.eth.clkMode = config[clkModeKey];
+ if (hwConfig.eth.pwrPin == -1)
{
- searchId = config["searchId"];
+ hwConfig.eth.pwrPin = config[pwrAltPinKey];
}
- ThisConfigStruct *newConfig = findBrdConfig(searchId);
- if (newConfig)
+ // hwConfig.eth.pwrAltPin = config[pwrAltPin];
+ hwConfig.mist.btnPin = config[btnPinKey];
+ hwConfig.mist.btnPlr = config[btnPlrKey];
+ hwConfig.mist.uartSelPin = config[uartSelPinKey];
+ hwConfig.mist.uartSelPlr = config[uartSelPlrKey];
+ hwConfig.mist.ledModePin = config[ledModePinKey];
+ hwConfig.mist.ledModePlr = config[ledModePlrKey];
+ hwConfig.mist.ledPwrPin = config[ledPwrPinKey];
+ hwConfig.mist.ledPwrPlr = config[ledPwrPlrKey];
+ hwConfig.zb.txPin = config[zbTxPinKey];
+ hwConfig.zb.rxPin = config[zbRxPinKey];
+ hwConfig.zb.rstPin = config[zbRstPinKey];
+ hwConfig.zb.bslPin = config[zbBslPinKey];
+
+ LOGD("Removing HW config file");
+ LittleFS.remove(configFileHw);
+ if (hwConfig.board[0] != '\0' && strlen(hwConfig.board) > 0)
{
- LOGD("Find. Saving config");
-
- DynamicJsonDocument config(512);
- config[board] = newConfig->board;
- config[addr] = newConfig->eth.addr;
- config[pwrPin] = newConfig->eth.pwrPin;
- config[mdcPin] = newConfig->eth.mdcPin;
- config[mdiPin] = newConfig->eth.mdiPin;
- config[phyType] = newConfig->eth.phyType;
- config[clkMode] = newConfig->eth.clkMode;
- config[pwrAltPin] = newConfig->eth.pwrAltPin;
- config[btnPin] = newConfig->mist.btnPin;
- config[btnPlr] = newConfig->mist.btnPlr;
- config[uartSelPin] = newConfig->mist.uartSelPin;
- config[uartSelPlr] = newConfig->mist.uartSelPlr;
- config[ledModePin] = newConfig->mist.ledModePin;
- config[ledModePlr] = newConfig->mist.ledModePlr;
- config[ledPwrPin] = newConfig->mist.ledPwrPin;
- config[ledPwrPlr] = newConfig->mist.ledPwrPlr;
- config[zbTxPin] = newConfig->zb.txPin;
- config[zbRxPin] = newConfig->zb.rxPin;
- config[zbRstPin] = newConfig->zb.rstPin;
- config[zbBslPin] = newConfig->zb.bslPin;
- writeDefaultConfig(configFileHw, config);
-
- LOGD("Calc and save temp offset");
- float CPUtemp = getCPUtemp(true);
- int offset = CPUtemp - 30;
- systemCfg.tempOffset = int(offset);
- saveSystemConfig(systemCfg);
-
- LOGD("Restarting...");
- ESP.restart();
+ LOGD("Load HW - OK");
+ saveHwConfig(hwConfig);
+ return true;
+ }
+ else
+ {
+ LOGI("Load HW - ERROR. File is empty");
+ return false;
}
}
- return false;
+ else
+ {
+ return false;
+ }
+}
+/*
+if (hwConfig.board[0] != '\0' && strlen(hwConfig.board) > 0)
+{
+ delay(3000);
+ LOGD("Load HW - OK");
+ saveHwConfig(hwConfig);
+ return true;
}
+else
+{
+ LOGI("Load HW - ERROR");
+
+ int searchId = 0;
+ if (config["searchId"])
+ {
+ searchId = config["searchId"];
+ }
+
+
+ String chipId = ESP.getChipModel();
+ LOGW("%s", chipId.c_str());
+ if (chipId == "ESP32-D0WDQ6")
+ {
+ searchId = 12;
+ }
+
+
+ ThisConfigStruct *newConfig = findBrdConfig(searchId);
+ if (newConfig)
+ {
+ LOGD("Find. Saving config");
+ saveHwConfig(*newConfig);
+
+
+ DynamicJsonDocument config(512);
+ config[boardKey] = newConfig->board;
+ config[addrKey] = newConfig->eth.addr;
+ config[pwrPinKey] = newConfig->eth.pwrPin;
+ config[mdcPinKey] = newConfig->eth.mdcPin;
+ config[mdiPinKey] = newConfig->eth.mdiPin;
+ config[phyTypeKey] = newConfig->eth.phyType;
+ config[clkModeKey] = newConfig->eth.clkMode;
+ // config[pwrAltPin] = newConfig->eth.pwrAltPin;
+ config[btnPinKey] = newConfig->mist.btnPin;
+ config[btnPlrKey] = newConfig->mist.btnPlr;
+ config[uartSelPinKey] = newConfig->mist.uartSelPin;
+ config[uartSelPlrKey] = newConfig->mist.uartSelPlr;
+ config[ledModePinKey] = newConfig->mist.ledModePin;
+ config[ledModePlrKey] = newConfig->mist.ledModePlr;
+ config[ledPwrPinKey] = newConfig->mist.ledPwrPin;
+ config[ledPwrPlrKey] = newConfig->mist.ledPwrPlr;
+ config[zbTxPinKey] = newConfig->zb.txPin;
+ config[zbRxPinKey] = newConfig->zb.rxPin;
+ config[zbRstPinKey] = newConfig->zb.rstPin;
+ config[zbBslPinKey] = newConfig->zb.bslPin;
+ writeDefaultConfig(configFileHw, config);
+
+
+ LOGD("Calc and save temp offset");
+ float CPUtemp = getCPUtemp(true);
+ int offset = CPUtemp - 30;
+ systemCfg.tempOffset = int(offset);
+ saveSystemConfig(systemCfg);
+
+ restartDevice();
+ }
+}
+return false;
+*/
/* Previous firmware read config support. start */
+/*
const char *msg_file_rm = "OK. Remove old file";
const char *msg_open_f = "Error. open failed";
@@ -942,7 +1171,7 @@ void fileReadError(DeserializationError error, const char *fileName)
{
fileContent += (char)configFile.read();
}
- LOGI("%s - %s - %s", fileName, error.f_str(), fileContent.c_str());
+ LOGI("%s - %s - %s", fileName, error.c_str(), fileContent.c_str());
configFile.close();
if (error == DeserializationError::EmptyInput)
{
@@ -951,12 +1180,13 @@ void fileReadError(DeserializationError error, const char *fileName)
}
}
+
bool loadFileSystemVar()
{
File configFile = LittleFS.open(configFileSystem, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileSystem, msg_open_f);
+ // LOGD("%s %s", configFileSystem, msg_open_f);
return false;
}
@@ -991,7 +1221,7 @@ bool loadFileConfigWifi()
File configFile = LittleFS.open(configFileWifi, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileWifi, msg_open_f);
+ // LOGD("%s %s", configFileWifi, msg_open_f);
return false;
}
@@ -1030,7 +1260,7 @@ bool loadFileConfigEther()
File configFile = LittleFS.open(configFileEther, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileEther, msg_open_f);
+ // LOGD("%s %s", configFileEther, msg_open_f);
return false;
}
@@ -1061,7 +1291,7 @@ bool loadFileConfigGeneral()
File configFile = LittleFS.open(configFileGeneral, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileGeneral, msg_open_f);
+ // LOGD("%s %s", configFileGeneral, msg_open_f);
return false;
}
@@ -1091,7 +1321,7 @@ bool loadFileConfigGeneral()
systemCfg.disableLedPwr = (uint8_t)doc[disableLedPwrKey];
systemCfg.disableLedUSB = (uint8_t)doc[disableLedUSBKey];
vars.disableLeds = (uint8_t)doc[disableLedsKey];
- systemCfg.keepWeb = (uint8_t)doc[keepWebKey];
+ // systemCfg.keepWeb = (uint8_t)doc[keepWebKey];
strlcpy(systemCfg.timeZone, doc[timeZoneKey] | NTP_TIME_ZONE, sizeof(systemCfg.timeZone));
configFile.close();
@@ -1106,7 +1336,7 @@ bool loadFileConfigSecurity()
File configFile = LittleFS.open(configFileSecurity, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileSecurity, msg_open_f);
+ // LOGD("%s %s", configFileSecurity, msg_open_f);
return false;
}
@@ -1134,6 +1364,7 @@ bool loadFileConfigSecurity()
return true;
}
+
bool loadFileConfigSerial()
{
const char *baud = "baud";
@@ -1141,7 +1372,7 @@ bool loadFileConfigSerial()
File configFile = LittleFS.open(configFileSerial, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileSerial, msg_open_f);
+ // LOGD("%s %s", configFileSerial, msg_open_f);
return false;
}
@@ -1170,7 +1401,7 @@ bool loadFileConfigMqtt()
File configFile = LittleFS.open(configFileMqtt, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileMqtt, msg_open_f);
+ // LOGD("%s %s", configFileMqtt, msg_open_f);
return false;
}
@@ -1212,7 +1443,7 @@ bool loadFileConfigWg()
File configFile = LittleFS.open(configFileWg, FILE_READ);
if (!configFile)
{
- LOGD("%s %s", configFileWg, msg_open_f);
+ // LOGD("%s %s", configFileWg, msg_open_f);
return false;
}
@@ -1242,4 +1473,6 @@ bool loadFileConfigWg()
return true;
}
+*/
+
/* Previous firmware read config support. end */
\ No newline at end of file
diff --git a/src/config.h b/src/config.h
index a7a8cb50..34e5a9bc 100644
--- a/src/config.h
+++ b/src/config.h
@@ -8,13 +8,14 @@
#include
#include
#include
+#include "const/hw.h"
#define DEBOUNCE_TIME 70
#define MAX_DEV_ID_LONG 50
#define ZB_TCP_PORT 6638 // any port ever. later setup from config file
#define ZB_SERIAL_SPEED 115200
-#define NTP_TIME_ZONE "Europe/Kiev"
+#define NTP_TIME_ZONE "Europe/Berlin"
#define NTP_SERV_1 "pool.ntp.org"
#define NTP_SERV_2 "time.google.com"
#define DNS_SERV_1 "1.1.1.1"
@@ -23,6 +24,8 @@
#define NETWORK_ZERO "0.0.0.0"
#define NM_START_TIME "23:00"
#define NM_END_TIME "07:00"
+#define UPD_CHK_TIME "01:00"
+#define UPD_CHK_DAY "*"
#define MAX_SOCKET_CLIENTS 5
@@ -34,7 +37,7 @@
#define NEED_BSL_PIN 15 // CC2652 pin number (FOR BSL VALIDATION!)
#define NEED_BSL_LEVEL 1 // 0-ERROR 1-LOW 2-HIGH
-const int16_t overseerInterval = 5 * 1000; // check lan or wifi connection every 5sec
+const int16_t overseerInterval = 5; // check lan or wifi connection every 5sec
const uint8_t overseerMaxRetry = 3; // 5x12 = 60sec delay for AP start
enum WORK_MODE_t : uint8_t
@@ -50,6 +53,14 @@ enum LED_t : uint8_t
ZB_LED
};
+enum ZB_ROLE_t : uint8_t
+{
+ UNDEFINED,
+ COORDINATOR,
+ ROUTER,
+ OPENTHREAD
+};
+
extern const char *coordMode; // coordMode node name
extern const char *configFileSystem;
extern const char *configFileWifi;
@@ -66,14 +77,16 @@ struct SysVarsStruct
bool hwBtnIs = false;
bool hwLedUsbIs = false;
bool hwLedPwrIs = false;
- bool hwUartSelIs = false;
+ // bool hwUartSelIs = false;
bool hwZigbeeIs = false;
+ bool oneWireIs = false;
bool connectedSocket[MAX_SOCKET_CLIENTS]; //[10]
int connectedClients;
unsigned long socketTime;
bool connectedEther = false;
+ bool ethIPv6 = false;
bool apStarted = false;
bool wifiWebSetupInProgress = false;
@@ -90,11 +103,24 @@ struct SysVarsStruct
bool disableLeds;
// bool zbLedState;
- // bool zbFlashing;
+ bool zbFlashing;
char deviceId[MAX_DEV_ID_LONG];
bool updateEspAvail;
+ bool updateZbAvail;
+
+ char lastESPVer[20];
+ char lastZBVer[20];
+ //IPAddress savedWifiDNS;
+ //IPAddress savedEthDNS;
+
+ bool firstUpdCheck = false;
+
+ uint32_t last1wAsk = 0;
+ float temp1w = 0;
+
+ bool needFsDownload = false;
};
// Network configuration structure
@@ -102,8 +128,11 @@ struct NetworkConfigStruct
{
// Wi-Fi
bool wifiEnable;
+ // int wifiPower;
+ wifi_power_t wifiPower;
+ int wifiMode;
char wifiSsid[50];
- char wifiPass[50];
+ char wifiPass[80];
bool wifiDhcp;
IPAddress wifiIp;
IPAddress wifiMask;
@@ -175,7 +204,7 @@ void loadMqttConfig(MqttConfigStruct &config);
struct SystemConfigStruct
{
- bool keepWeb; // when usb mode active
+ // bool keepWeb; // when usb mode active
bool disableWeb; // when socket connected
bool webAuth;
@@ -183,7 +212,8 @@ struct SystemConfigStruct
char webPass[50];
bool fwEnabled; // firewall for socket connection
- IPAddress fwIp; // allowed IP
+ IPAddress fwIp; // allowed IP base
+ IPAddress fwMask; // allowed mask
int serialSpeed;
int socketPort;
@@ -205,7 +235,14 @@ struct SystemConfigStruct
char nmEnd[6];
// WORK_MODE_t prevWorkMode; // for button // WORK_MODE_t
- WORK_MODE_t workMode; // for button // WORK_MODE_t
+ WORK_MODE_t workMode;
+
+ ZB_ROLE_t zbRole;
+ char zbFw[30];
+
+ char updCheckTime[6];
+ char updCheckDay[3];
+ bool updAutoInst;
};
// Function prototypes for SystemConfigStruct
@@ -218,6 +255,7 @@ void serializeVpnConfigToJson(const VpnConfigStruct &config, JsonObject obj);
void serializeMqttConfigToJson(const MqttConfigStruct &config, JsonObject obj);
void serializeSystemConfigToJson(const SystemConfigStruct &config, JsonObject obj);
void serializeSysVarsToJson(const SysVarsStruct &vars, JsonObject obj);
+void serializeHwConfigToJson(const ThisConfigStruct &config, JsonObject obj);
void updateConfiguration(WebServer &server, SystemConfigStruct &configSys, NetworkConfigStruct &configNet, VpnConfigStruct &configVpn, MqttConfigStruct &configMqtt);
@@ -232,11 +270,16 @@ String makeJsonConfig(const NetworkConfigStruct *networkCfg = nullptr,
const VpnConfigStruct *vpnCfg = nullptr,
const MqttConfigStruct *mqttCfg = nullptr,
const SystemConfigStruct *systemCfg = nullptr,
- const SysVarsStruct *systemVars = nullptr);
+ const SysVarsStruct *systemVars = nullptr,
+ const ThisConfigStruct *hwCfg = nullptr);
bool loadFileConfigHW();
+void saveHwConfig(const ThisConfigStruct &config);
+void loadHwConfig(ThisConfigStruct &config);
+
/* Previous firmware read config support. start */
+/*
bool loadFileSystemVar();
bool loadFileConfigWifi();
bool loadFileConfigEther();
@@ -245,6 +288,7 @@ bool loadFileConfigSecurity();
bool loadFileConfigSerial();
bool loadFileConfigMqtt();
bool loadFileConfigWg();
+*/
/* Previous firmware read config support. end */
/* ----- Define functions | START -----*/
@@ -274,16 +318,16 @@ uint8_t temprature_sens_read();
// Set the current logging level here
#define CURRENT_LOG_LEVEL LOG_LEVEL_DEBUG
-#define DEBUG_PRINT(x) Serial.print(String(x))
-#define DEBUG_PRINTLN(x) Serial.println(String(x))
+//#define DEBUG_PRINT(x) Serial.print(String(x))
+//#define DEBUG_PRINTLN(x) Serial.println(String(x))
#else
// Set the current logging level here
#define CURRENT_LOG_LEVEL LOG_LEVEL_INFO
-#define DEBUG_PRINT(x)
-#define DEBUG_PRINTLN(x)
+//#define DEBUG_PRINT(x)
+//#define DEBUG_PRINTLN(x)
#endif
#endif
@@ -297,19 +341,31 @@ uint8_t temprature_sens_read();
// Conditional logging macros
#if CURRENT_LOG_LEVEL >= LOG_LEVEL_WARN
-#define LOGW(format, ...) Serial.printf(ANSI_COLOR_PURPLE "%d " ANSI_COLOR_RESET ANSI_COLOR_RED "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__)
+#define LOGW(format, ...) \
+ if (systemCfg.workMode == WORK_MODE_NETWORK) \
+ { \
+ Serial.printf(ANSI_COLOR_PURPLE "%lu " ANSI_COLOR_RESET ANSI_COLOR_RED "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__); \
+ }
#else
#define LOGW(format, ...) // Nothing
#endif
#if CURRENT_LOG_LEVEL >= LOG_LEVEL_INFO
-#define LOGI(format, ...) Serial.printf(ANSI_COLOR_PURPLE "%d " ANSI_COLOR_RESET ANSI_COLOR_GREEN "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__)
+#define LOGI(format, ...) \
+ if (systemCfg.workMode == WORK_MODE_NETWORK) \
+ { \
+ Serial.printf(ANSI_COLOR_PURPLE "%lu " ANSI_COLOR_RESET ANSI_COLOR_GREEN "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__); \
+ }
#else
#define LOGI(format, ...) // Nothing
#endif
#if CURRENT_LOG_LEVEL >= LOG_LEVEL_DEBUG
-#define LOGD(format, ...) Serial.printf(ANSI_COLOR_PURPLE "%d " ANSI_COLOR_RESET ANSI_COLOR_YELLOW "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__)
+#define LOGD(format, ...) \
+ if (systemCfg.workMode == WORK_MODE_NETWORK) \
+ { \
+ Serial.printf(ANSI_COLOR_PURPLE "%lu " ANSI_COLOR_RESET ANSI_COLOR_YELLOW "[%s] " ANSI_COLOR_RESET format "\n", millis(), __func__, ##__VA_ARGS__); \
+ }
#else
#define LOGD(format, ...) // Nothing
#endif
@@ -343,8 +399,14 @@ struct LEDControl
LEDSettings powerLED;
};
-enum usbMode
+enum usbMode : uint8_t
{
XZG,
ZIGBEE
};
+
+enum updInfoType : uint8_t
+{
+ UPD_ESP,
+ UPD_ZB
+};
\ No newline at end of file
diff --git a/src/const/hw.cpp b/src/const/hw.cpp
index f47991f9..d5c57532 100644
--- a/src/const/hw.cpp
+++ b/src/const/hw.cpp
@@ -1,46 +1,51 @@
#include "const/hw.h"
// Ethernet configurations
-// !!! Don't forget to edit ETH_CFG_CNT !!!
+// Don't forget to edit ETH_CFG_CNT !
EthConfig ethConfigs[] = {
- {.addr = 0, .pwrPin = 12, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = -1}, // 0 Olimex-ESP32-POE
- {.addr = 1, .pwrPin = 16, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO0_IN, .pwrAltPin = -1}, // 1 WT32-ETH01
- {.addr = 0, .pwrPin = -1, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = 5}, // 2 T-Internet-POE
+ {.addr = 0, .pwrPin = 12, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT}, // .pwrAltPin = -1}, // 0 Olimex-ESP32-POE
+ {.addr = 1, .pwrPin = 16, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO0_IN}, // .pwrAltPin = -1}, // 1 WT32-ETH01 / SLZB-06
+ {.addr = 0, .pwrPin = 5, .mdcPin = 23, .mdiPin = 18, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT}, // .pwrAltPin = -1}, // 2 T-Internet-POE / UZG-01 / HamGeek POE Plus
};
// ZigBee configurations
-// !!! Don't forget to edit ZB_CFG_CNT !!!
+// Don't forget to edit ZB_CFG_CNT !
ZbConfig zbConfigs[] = {
- {.txPin = 4, .rxPin = 36, .rstPin = 16, .bslPin = 32}, // 0
- {.txPin = 17, .rxPin = 5, .rstPin = 33, .bslPin = 32}, // 1
- {.txPin = 33, .rxPin = 32, .rstPin = 12, .bslPin = 14}, // 2
- {.txPin = 4, .rxPin = 36, .rstPin = 5, .bslPin = 16}, // 3
- {.txPin = 5, .rxPin = 17, .rstPin = 33, .bslPin = 32}, // 4
- {.txPin = 16, .rxPin = 5, .rstPin = 33, .bslPin = 32}, // 5
- {.txPin = 16, .rxPin = 5, .rstPin = 13, .bslPin = 4}, // 6
- {.txPin = 4, .rxPin = 36, .rstPin = 5, .bslPin = 16}, // 7
+ {.txPin = 4, .rxPin = 36, .rstPin = 16, .bslPin = 32}, // 0 UZG-01 / LilyZig / Olizig
+ {.txPin = 17, .rxPin = 5, .rstPin = 33, .bslPin = 32}, // 1 ZigStar LAN / SLZB-06 / TubesZB-eth
+ {.txPin = 33, .rxPin = 32, .rstPin = 12, .bslPin = 14}, // 2 No name China-GW
+ {.txPin = 5, .rxPin = 17, .rstPin = 33, .bslPin = 32}, // 3 TubesZB-eth_usb
+ {.txPin = 16, .rxPin = 5, .rstPin = 33, .bslPin = 32}, // 4 TubesZB-poe
+ {.txPin = 16, .rxPin = 5, .rstPin = 13, .bslPin = 4}, // 5 TubesZB-poe-2022
+ {.txPin = 4, .rxPin = 36, .rstPin = 5, .bslPin = 16}, // 6 TubesZB-poe-2023
+ {.txPin = 23, .rxPin = 22, .rstPin = 18, .bslPin = 19}, // 7 SLS-classic
};
// Mist configurations
-// !!! Don't forget to edit MIST_CFG_CNT !!!
+// Don't forget to edit MIST_CFG_CNT !
MistConfig mistConfigs[] = {
- {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledModePin = -1, .ledModePlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, // 0
- {.btnPin = 35, .btnPlr = 1, .uartSelPin = 33, .uartSelPlr = 1, .ledModePin = 12, .ledModePlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, // 1
- {.btnPin = 35, .btnPlr = 1, .uartSelPin = 4, .uartSelPlr = 1, .ledModePin = 12, .ledModePlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, // 2
+ {.btnPin = -1, .btnPlr = 0, .uartSelPin = -1, .uartSelPlr = 0, .ledModePin = -1, .ledModePlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, // 0 No mist cfg
+ {.btnPin = 35, .btnPlr = 1, .uartSelPin = 33, .uartSelPlr = 1, .ledModePin = 12, .ledModePlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, // 1 UZG-01 / CZC-1.0
+ {.btnPin = 35, .btnPlr = 1, .uartSelPin = 4, .uartSelPlr = 1, .ledModePin = 12, .ledModePlr = 1, .ledPwrPin = 14, .ledPwrPlr = 1}, // 2 SLZB-06
+ {.btnPin = 33, .btnPlr = 1, .uartSelPin = -1, .uartSelPlr = 0, .ledModePin = -1, .ledModePlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, // 3 SLS-classic
+ {.btnPin = 14, .btnPlr = 1, .uartSelPin = -1, .uartSelPlr = 0, .ledModePin = -1, .ledModePlr = 0, .ledPwrPin = -1, .ledPwrPlr = 0}, // 4 T-Internet-POE
};
// Board configurations
-// !!! Don't forget to edit BOARD_CFG_CNT !!!
+// Don't forget to edit BOARD_CFG_CNT !
BrdConfigStruct brdConfigs[] = {
- {"UZG-01", .ethConfigIndex = 2, .zbConfigIndex = 0, .mistConfigIndex = 1},
- {"SLZB-06", .ethConfigIndex = 1, .zbConfigIndex = 1, .mistConfigIndex = 2},
- {"WT32-ETH01", .ethConfigIndex = 1, .zbConfigIndex = 1, .mistConfigIndex = 0},
- {"T-Internet-POE", .ethConfigIndex = 2, .zbConfigIndex = 0, .mistConfigIndex = 0},
- {"Olimex-ESP32-POE", .ethConfigIndex = 0, .zbConfigIndex = 0, .mistConfigIndex = 0},
- {"China-GW", .ethConfigIndex = 0, .zbConfigIndex = 2, .mistConfigIndex = 0},
- {"TubesZB-eth", .ethConfigIndex = 1, .zbConfigIndex = 1, .mistConfigIndex = 0},
- {"TubesZB-eth_usb", .ethConfigIndex = 1, .zbConfigIndex = 4, .mistConfigIndex = 0},
- {"TubesZB-poe", .ethConfigIndex = 0, .zbConfigIndex = 5, .mistConfigIndex = 0},
- {"TubesZB-poe-2022", .ethConfigIndex = 0, .zbConfigIndex = 6, .mistConfigIndex = 0},
- {"TubesZB-poe-2023", .ethConfigIndex = 0, .zbConfigIndex = 7, .mistConfigIndex = 0},
-};
+ {"SLS-classic", -1, 7, 3}, // 0
+ {"UZG-01", 2, 0, 1}, // 1
+ {"SLZB-06", 1, 1, 2}, // 2
+ {"ZigStar LAN", 1, 1, 0}, // 3
+ {"LilyZig", 2, 0, 4}, // 4
+ {"Olizig", 0, 0, 0}, // 5
+ {"China-GW", 0, 2, 0}, // 6
+ {"TubesZB-eth", 1, 1, 0}, // 7
+ {"TubesZB-eth_usb", 1, 3, 0}, // 8
+ {"TubesZB-poe", 0, 4, 0}, // 9
+ {"TubesZB-poe-2022", 0, 5, 0}, // 10
+ {"TubesZB-poe-2023", 0, 6, 0}, // 11
+ {"CZC-1.0", 2, 0, 1}, // 12
+ {"HG POE Plus", 2, 0, 1}, // 13
+};
\ No newline at end of file
diff --git a/src/const/hw.h b/src/const/hw.h
index 357307b0..15058231 100644
--- a/src/const/hw.h
+++ b/src/const/hw.h
@@ -1,3 +1,6 @@
+#ifndef HW_H
+#define HW_H
+
#include
// Ethernet settings structure
@@ -9,7 +12,7 @@ struct EthConfig
int mdiPin;
eth_phy_type_t phyType;
eth_clock_mode_t clkMode;
- int pwrAltPin;
+ //int pwrAltPin;
};
// ZigBee settings structure
@@ -45,8 +48,8 @@ struct BrdConfigStruct
#define ETH_CFG_CNT 3
#define ZB_CFG_CNT 8
-#define MIST_CFG_CNT 3
-#define BOARD_CFG_CNT 13
+#define MIST_CFG_CNT 5
+#define BOARD_CFG_CNT 14
struct ThisConfigStruct
{
@@ -54,4 +57,6 @@ struct ThisConfigStruct
EthConfig eth;
ZbConfig zb;
MistConfig mist;
-};
\ No newline at end of file
+};
+
+#endif // HW_H
\ No newline at end of file
diff --git a/src/const/keys.cpp b/src/const/keys.cpp
index a7d2d4ef..9290d775 100644
--- a/src/const/keys.cpp
+++ b/src/const/keys.cpp
@@ -10,6 +10,9 @@ const char *wifiMaskKey = "wifiMask";
const char *wifiGateKey = "wifiGate";
const char *wifiDns1Key = "wifiDns1";
const char *wifiDns2Key = "wifiDns2";
+const char *wifiPwrKey = "wifiPwr";
+const char *wifiModeKey = "wifiMode";
+const char *wifiIPv6Key = "wifiIPv6";
const char *ethEnblKey = "ethEnbl";
const char *ethDhcpKey = "ethDhcp";
const char *ethIpKey = "ethIp";
@@ -17,6 +20,7 @@ const char *ethMaskKey = "ethMask";
const char *ethGateKey = "ethGate";
const char *ethDns1Key = "ethDns1";
const char *ethDns2Key = "ethDns2";
+const char *ethIPv6Key = "ethIPv6";
const char *vpnConfigKey = "vpn-config";
const char *wgEnableKey = "wgEnable";
@@ -51,13 +55,14 @@ const char *discoveryKey = "discovery";
const char *reconnectIntKey = "reconnectInt";
const char *systemConfigKey = "system-config";
-const char *keepWebKey = "keepWeb";
+// const char *keepWebKey = "keepWeb";
const char *disableWebKey = "disableWeb";
const char *webAuthKey = "webAuth";
const char *webUserKey = "webUser";
const char *webPassKey = "webPass";
const char *fwEnabledKey = "fwEnabled";
const char *fwIpKey = "fwIp";
+const char *fwMaskKey = "fwMask";
const char *serialSpeedKey = "serialSpeed";
const char *socketPortKey = "socketPort";
const char *tempOffsetKey = "tempOffset";
@@ -73,11 +78,15 @@ const char *nmStartHourKey = "startHour";
const char *nmEndHourKey = "endHour";
const char *nmEnableKey = "nightMode";
+const char *updCheckTimeKey = "updHour";
+const char *updCheckDayKey = "updDays";
+const char *updAutoInstKey = "autoIns";
+
const char *systemVarsKey = "system-vars";
const char *hwBtnIsKey = "hwBtnIs";
const char *hwLedUsbIsKey = "hwLedUsbIs";
const char *hwLedPwrIsKey = "hwLedPwrIs";
-const char *hwUartSelIsKey = "hwUartSelIs";
+// const char *hwUartSelIsKey = "hwUartSelIs";
const char *hwZigbeeIsKey = "hwZigbeeIs";
const char *workModeKey = "workMode";
const char *connectedSocketKey = "connectedSocket";
@@ -94,8 +103,41 @@ const char *vpnHnInitKey = "vpnHnInit";
const char *mqttConnKey = "mqttConn";
const char *mqttReconnectTimeKey = "mqttReconnectTime";
const char *mqttHeartbeatTimeKey = "mqttHeartbeatTime";
-//const char *zbLedStateKey = "zbLedState";
-//const char *zbFlashingKey = "zbFlashing";
+// const char *zbLedStateKey = "zbLedState";
+const char *zbFlashingKey = "zbFlashing";
const char *deviceIdKey = "deviceId";
+const char *timeZoneNameKey = "timeZoneName";
+const char *zbRoleKey = "zbRole";
+const char *zbFwKey = "zbFw";
+const char *rcpUpdAvailKey = "rcpUpdAvail";
+const char *espUpdAvailKey = "espUpdAvail";
+
+const char *tagZB_FW_info = "zb.fi";
+const char *tagZB_FW_file = "zb.ff";
+const char *tagZB_FW_err = "zb.fe";
+const char *tagZB_FW_prgs = "zb.fp";
+const char *tagZB_NV_prgs = "zb.nv";
+const char *tagESP_FW_prgs = "esp.fp";
-const char *timeZoneNameKey = "timeZoneName";
\ No newline at end of file
+const char *hwConfigKey = "hw-config";
+const char *boardKey = "board";
+const char *addrKey = "addr";
+const char *pwrPinKey = "pwrPin";
+const char *mdcPinKey = "mdcPin";
+const char *mdiPinKey = "mdiPin";
+const char *phyTypeKey = "phyType";
+const char *clkModeKey = "clkMode";
+const char *pwrAltPinKey = "pwrAltPin";
+const char *btnPinKey = "btnPin";
+const char *btnPlrKey = "btnPlr";
+const char *uartSelPinKey = "uartSelPin";
+const char *uartSelPlrKey = "uartSelPlr";
+const char *ledModePinKey = "ledModePin";
+const char *ledModePlrKey = "ledModePlr";
+const char *ledPwrPinKey = "ledPwrPin";
+const char *ledPwrPlrKey = "ledPwrPlr";
+const char *zbTxPinKey = "zbTxPin";
+const char *zbRxPinKey = "zbRxPin";
+const char *zbRstPinKey = "zbRstPin";
+const char *zbBslPinKey = "zbBslPin";
+const char *contTypeText = "text/plain";
\ No newline at end of file
diff --git a/src/const/keys.h b/src/const/keys.h
index 567abc26..1496d3c3 100644
--- a/src/const/keys.h
+++ b/src/const/keys.h
@@ -12,6 +12,9 @@ extern const char *wifiMaskKey;
extern const char *wifiGateKey;
extern const char *wifiDns1Key;
extern const char *wifiDns2Key;
+extern const char *wifiPwrKey;
+extern const char *wifiModeKey;
+extern const char *wifiIPv6Key;
extern const char *ethEnblKey;
extern const char *ethDhcpKey;
extern const char *ethIpKey;
@@ -19,6 +22,7 @@ extern const char *ethMaskKey;
extern const char *ethGateKey;
extern const char *ethDns1Key;
extern const char *ethDns2Key;
+extern const char *ethIPv6Key;
extern const char *vpnConfigKey;
extern const char *wgEnableKey;
extern const char *wgLocalIPKey;
@@ -56,6 +60,7 @@ extern const char *webUserKey;
extern const char *webPassKey;
extern const char *fwEnabledKey;
extern const char *fwIpKey;
+extern const char *fwMaskKey;
extern const char *serialSpeedKey;
extern const char *socketPortKey;
extern const char *tempOffsetKey;
@@ -70,6 +75,9 @@ extern const char *ntpServ2Key;
extern const char *nmStartHourKey;
extern const char *nmEndHourKey;
extern const char *nmEnableKey;
+extern const char *updCheckTimeKey;
+extern const char *updCheckDayKey;
+extern const char *updAutoInstKey;
extern const char *systemVarsKey;
extern const char *hwBtnIsKey;
extern const char *hwLedUsbIsKey;
@@ -95,5 +103,37 @@ extern const char *zbLedStateKey;
extern const char *zbFlashingKey;
extern const char *deviceIdKey;
extern const char *timeZoneNameKey;
+extern const char *zbRoleKey;
+extern const char *zbFwKey;
+extern const char *rcpUpdAvailKey;
+extern const char *espUpdAvailKey;
+extern const char *tagZB_FW_info;
+extern const char *tagZB_FW_file;
+extern const char *tagZB_FW_err;
+extern const char *tagZB_FW_prgs;
+extern const char *tagZB_NV_prgs;
+extern const char *tagESP_FW_prgs;
+extern const char *hwConfigKey;
+extern const char *boardKey;
+extern const char *addrKey;
+extern const char *pwrPinKey;
+extern const char *mdcPinKey;
+extern const char *mdiPinKey;
+extern const char *phyTypeKey;
+extern const char *clkModeKey;
+extern const char *pwrAltPinKey;
+extern const char *btnPinKey;
+extern const char *btnPlrKey;
+extern const char *uartSelPinKey;
+extern const char *uartSelPlrKey;
+extern const char *ledModePinKey;
+extern const char *ledModePlrKey;
+extern const char *ledPwrPinKey;
+extern const char *ledPwrPlrKey;
+extern const char *zbTxPinKey;
+extern const char *zbRxPinKey;
+extern const char *zbRstPinKey;
+extern const char *zbBslPinKey;
+extern const char *contTypeText;
#endif // XZG_KEYS_H
diff --git a/src/etc.cpp b/src/etc.cpp
index 7bbc6e49..8da401db 100644
--- a/src/etc.cpp
+++ b/src/etc.cpp
@@ -16,6 +16,7 @@
#include "const/zones.h"
// #include "const/hw.h"
#include "zb.h"
+#include "main.h"
#include
static WireGuard wg;
@@ -41,14 +42,14 @@ extern CCTools CCTool;
const char *coordMode = "coordMode"; // coordMode node name ?? not name but text field with mode
// const char *prevCoordMode = "prevCoordMode"; // prevCoordMode node name ?? not name but text field with mode
-const char *configFileSystem = "/config/system.json";
+/*const char *configFileSystem = "/config/system.json";
const char *configFileWifi = "/config/configWifi.json";
const char *configFileEther = "/config/configEther.json";
const char *configFileGeneral = "/config/configGeneral.json";
const char *configFileSecurity = "/config/configSecurity.json";
const char *configFileSerial = "/config/configSerial.json";
const char *configFileMqtt = "/config/configMqtt.json";
-const char *configFileWg = "/config/configWg.json";
+const char *configFileWg = "/config/configWg.json";*/
const char *configFileHw = "/configHw.json";
#include "mbedtls/md.h"
@@ -88,6 +89,106 @@ String sha1(String payloadStr)
return hashStr;
}
+// #include
+// #include
+
+// OneWire *oneWire = nullptr;
+// DallasTemperature *sensor = nullptr;
+#include "DS18B20.h"
+
+OneWire *oneWire = nullptr;
+DS18B20 *sensor = nullptr;
+
+int check1wire()
+{
+ int pin = -1;
+ vars.oneWireIs = false;
+ if (hwConfig.eth.mdcPin != 33 && hwConfig.eth.mdiPin != 33 && hwConfig.eth.pwrPin != 33)
+ {
+ if (hwConfig.zb.rxPin != 33 && hwConfig.zb.txPin != 33 && hwConfig.zb.bslPin != 33 && hwConfig.zb.rstPin != 33)
+ {
+ if (hwConfig.mist.btnPin != 33 && hwConfig.mist.uartSelPin != 33 && hwConfig.mist.ledModePin != 33 && hwConfig.mist.ledPwrPin != 33)
+ {
+ pin = 33;
+ vars.oneWireIs = true;
+ }
+ }
+ }
+ return pin;
+}
+
+void setup1wire(int pin)
+{
+
+ if (pin > 0)
+ {
+ if (oneWire != nullptr)
+ {
+ delete oneWire;
+ }
+ if (sensor != nullptr)
+ {
+ delete sensor;
+ }
+
+ oneWire = new OneWire(pin);
+ sensor = new DS18B20(oneWire);
+
+ sensor->begin();
+ sensor->setResolution(10);
+
+#ifdef DEBUG
+ uint32_t start, stop;
+
+ start = micros();
+ sensor->requestTemperatures();
+
+ int n = 0;
+ // wait until sensor ready, do some counting for fun.
+ while (!sensor->isConversionComplete())
+ n++;
+
+ stop = micros();
+ LOGD("Convert %lu\t%d", stop - start, n);
+
+ // delay(100);
+ start = micros();
+ float f = sensor->getTempC();
+ stop = micros();
+
+ LOGD("getTemp %lu\t%.2f", stop - start, f);
+#endif
+
+ get1wire();
+ }
+}
+
+float get1wire()
+{
+
+ if (sensor == nullptr)
+ {
+ LOGW("1w not init");
+ vars.oneWireIs = false;
+ return -127.0;
+ }
+ if (millis() - vars.last1wAsk > 5000)
+ {
+ sensor->requestTemperatures();
+ vars.temp1w = sensor->getTempC();
+ LOGD("Temp is %f", vars.temp1w);
+ vars.last1wAsk = millis();
+ }
+
+ if (vars.temp1w == -127)
+ {
+ vars.oneWireIs = false;
+ LOGW("1w not connected");
+ }
+
+ return vars.temp1w;
+}
+
void getReadableTime(String &readableTime, unsigned long beginTime)
{
unsigned long currentMillis;
@@ -167,6 +268,11 @@ void zigbeeEnableBSL()
printLogMsg("ZB enable BSL");
CCTool.enterBSL();
printLogMsg("Now you can flash CC2652!");
+ if (systemCfg.workMode == WORK_MODE_USB)
+ {
+ Serial.updateBaudRate(500000);
+ Serial2.updateBaudRate(500000);
+ }
}
void zigbeeRestart()
@@ -174,30 +280,44 @@ void zigbeeRestart()
printLogMsg("ZB RST begin");
CCTool.restart();
printLogMsg("ZB restart was done");
+ if (systemCfg.workMode == WORK_MODE_USB)
+ {
+ Serial.updateBaudRate(systemCfg.serialSpeed);
+ Serial2.updateBaudRate(systemCfg.serialSpeed);
+ }
}
void usbModeSet(usbMode mode)
{
- if (vars.hwUartSelIs)
+ // if (vars.hwUartSelIs)
+ //{
+ // String modeStr = (mode == ZIGBEE) ? "ZIGBEE" : "ESP";
+ bool pinValue = (mode == ZIGBEE) ? HIGH : LOW;
+ // String msg = "Switched USB to " + modeStr + "";
+ // printLogMsg(msg);
+
+ if (mode == ZIGBEE)
{
- String modeStr = (mode == ZIGBEE) ? "ZIGBEE" : "ESP";
- bool pinValue = (mode == ZIGBEE) ? HIGH : LOW;
- String msg = "Switched USB to " + modeStr + "";
- printLogMsg(msg);
- digitalWrite(hwConfig.mist.uartSelPin, pinValue);
- if (pinValue)
- {
- ledControl.modeLED.mode = LED_ON;
- }
- else
- {
- ledControl.modeLED.mode = LED_OFF;
- }
+ Serial.updateBaudRate(systemCfg.serialSpeed);
}
else
{
- LOGD("NO vars.hwUartSelIs");
+ Serial.updateBaudRate(115200);
}
+ // digitalWrite(hwConfig.mist.uartSelPin, pinValue);
+ if (pinValue)
+ {
+ ledControl.modeLED.mode = LED_ON;
+ }
+ else
+ {
+ ledControl.modeLED.mode = LED_OFF;
+ }
+ //}
+ // else
+ //{
+ // LOGD("NO vars.hwUartSelIs");
+ //}
}
void getDeviceID(char *arr)
@@ -230,10 +350,10 @@ void getDeviceID(char *arr)
// sprintf(arr, "%s-%s", hwConfig.board, buf);
String devicePref = "XZG"; // hwConfig.board
- snprintf(arr, MAX_DEV_ID_LONG, "%s-%s", devicePref, buf);
+ snprintf(arr, MAX_DEV_ID_LONG + 1, "%s-%s", devicePref.c_str(), buf);
}
-void writeDefaultConfig(const char *path, DynamicJsonDocument &doc)
+/*void writeDefaultConfig(const char *path, DynamicJsonDocument &doc)
{
LOGD("Write defaults to %s", path);
serializeJsonPretty(doc, Serial);
@@ -244,8 +364,7 @@ void writeDefaultConfig(const char *path, DynamicJsonDocument &doc)
if (LittleFS.mkdir(path))
{
LOGD("Config dir created");
- delay(500);
- ESP.restart();
+ estartDevice();
}
else
{
@@ -258,7 +377,7 @@ void writeDefaultConfig(const char *path, DynamicJsonDocument &doc)
serializeJsonPretty(doc, configFile);
}
configFile.close();
-}
+}*/
void factoryReset()
{
@@ -268,37 +387,41 @@ void factoryReset()
ledControl.powerLED.mode = LED_FLASH_3Hz;
ledControl.modeLED.mode = LED_FLASH_3Hz;
- for (uint8_t i = 0; i < TIMEOUT_FACTORY_RESET; i++)
+ /*for (uint8_t i = 0; i < TIMEOUT_FACTORY_RESET; i++)
{
LOGD("%d, sec", TIMEOUT_FACTORY_RESET - i);
delay(1000);
- }
+ }*/
+ /*LittleFS.format();
if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED, "/lfs2", 10)) // change to format anyway
{
LOGD("Error with LITTLEFS");
- }
- LittleFS.remove(configFileSerial);
+ }*/
+
+ /*LittleFS.remove(configFileSerial);
LittleFS.remove(configFileSecurity);
LittleFS.remove(configFileGeneral);
LittleFS.remove(configFileEther);
LittleFS.remove(configFileWifi);
LittleFS.remove(configFileSystem);
- LittleFS.remove(configFileWg);
- LittleFS.remove(configFileHw);
LittleFS.remove(configFileMqtt);
- LOGD("FS Done");
+ LittleFS.remove(configFileWg);*/
+ // LittleFS.remove(configFileHw);
+
+ // LOGD("FS Done");
+
eraseNVS();
LOGD("NVS Done");
ledControl.powerLED.mode = LED_OFF;
ledControl.modeLED.mode = LED_OFF;
- delay(500);
- ESP.restart();
+ restartDevice();
}
void setClock(void *pvParameters)
{
+ // checkDNS();
configTime(0, 0, systemCfg.ntpServ1, systemCfg.ntpServ2);
const time_t targetTime = 946684800; // 946684800 - is 01.01.2000 in timestamp
@@ -321,7 +444,7 @@ void setClock(void *pvParameters)
{
// LOGD("Current GMT time: %s", String(asctime(&timeinfo)).c_str());
- char *zoneToFind = const_cast("Europe/Kiev");
+ char *zoneToFind = const_cast(NTP_TIME_ZONE);
if (systemCfg.timeZone)
{
zoneToFind = systemCfg.timeZone;
@@ -354,7 +477,7 @@ void setLedsDisable(bool all)
{
if (vars.hwLedPwrIs || vars.hwLedUsbIs)
{
- LOGD("setLedsDisable", "%s", String(all));
+ LOGD("[setLedsDisable] %s", String(all).c_str());
if (all)
{
ledControl.powerLED.active = false;
@@ -379,12 +502,128 @@ void nmDeactivate()
LOGD("end");
setLedsDisable();
}
+/*
+bool checkDNS(bool setup)
+{
+ const char *wifiKey = "WiFi";
+ const char *ethKey = "ETH";
+ const char *savedKey = "Saved";
+ const char *restoredKey = "Restored";
+ const char *dnsTagKey = "[DNS]";
+ char buffer[100];
+
+ if (networkCfg.wifiEnable)
+ {
+ IPAddress currentWifiDNS = WiFi.dnsIP();
+ if (currentWifiDNS != vars.savedWifiDNS)
+ {
+ char dnsStrW[16];
+ snprintf(dnsStrW, sizeof(dnsStrW), "%u.%u.%u.%u", currentWifiDNS[0], currentWifiDNS[1], currentWifiDNS[2], currentWifiDNS[3]);
+
+ int lastDot = -1;
+ for (int i = 0; dnsStrW[i] != '\0'; i++)
+ {
+ if (dnsStrW[i] == '.')
+ {
+ lastDot = i;
+ }
+ }
+
+ int fourthPartW = atoi(dnsStrW + lastDot + 1);
+
+ if (setup && fourthPartW != 0)
+ {
+ vars.savedWifiDNS = currentWifiDNS;
+ snprintf(buffer, sizeof(buffer), "%s %s %s - %s", dnsTagKey, savedKey, wifiKey, dnsStrW);
+ printLogMsg(buffer);
+ }
+ else
+ {
+ if (vars.savedWifiDNS)
+ {
+ WiFi.config(WiFi.localIP(), WiFi.gatewayIP(), WiFi.subnetMask(), vars.savedWifiDNS);
+ snprintf(buffer, sizeof(buffer), "%s %s %s - %s", dnsTagKey, restoredKey, wifiKey, vars.savedWifiDNS.toString().c_str());
+ printLogMsg(buffer);
+ }
+ }
+ }
+ }
+
+ if (networkCfg.ethEnable)
+ {
+ IPAddress currentEthDNS = ETH.dnsIP();
+ if (currentEthDNS != vars.savedEthDNS)
+ {
+ char dnsStrE[16];
+ snprintf(dnsStrE, sizeof(dnsStrE), "%u.%u.%u.%u", currentEthDNS[0], currentEthDNS[1], currentEthDNS[2], currentEthDNS[3]);
+
+ int lastDot = -1;
+ for (int i = 0; dnsStrE[i] != '\0'; i++)
+ {
+ if (dnsStrE[i] == '.')
+ {
+ lastDot = i;
+ }
+ }
+
+ int fourthPartE = atoi(dnsStrE + lastDot + 1);
+
+ if (setup && fourthPartE != 0)
+ {
+ vars.savedEthDNS = currentEthDNS;
+ snprintf(buffer, sizeof(buffer), "%s %s %s - %s", dnsTagKey, savedKey, ethKey, dnsStrE);
+ printLogMsg(buffer);
+ }
+ else
+ {
+ if (vars.savedEthDNS)
+ {
+ ETH.config(ETH.localIP(), ETH.gatewayIP(), ETH.subnetMask(), vars.savedEthDNS);
+ snprintf(buffer, sizeof(buffer), "%s %s %s - %s", dnsTagKey, restoredKey, ethKey, vars.savedEthDNS.toString().c_str());
+ printLogMsg(buffer);
+ }
+ }
+ }
+ }
+ return true;
+}
+*/
+
+/*void reCheckDNS()
+{
+ checkDNS();
+}*/
void setupCron()
{
- // Cron.create(const_cast("0 */1 * * * *"), cronTest, false);
+ // Cron.create(const_cast("30 */1 * * * *"), reCheckDNS, false);
+
+ // const String time = systemCfg.updCheckTime;
+ static char formattedTime[16];
+ int seconds, hours, minutes;
+
+ String wday = systemCfg.updCheckDay;
+
+ if (wday != "0")
+ {
+ seconds = random(1, 59);
+
+ // char timeArray[6];
+ // String(systemCfg.updCheckTime).toCharArray(timeArray, sizeof(timeArray));
+
+ sscanf(systemCfg.updCheckTime, "%d:%d", &hours, &minutes);
+
+ snprintf(formattedTime, sizeof(formattedTime), "%d %d %d * * %s", seconds, minutes, hours, wday.c_str());
- Cron.create(const_cast("0 0 */1 * * *"), checkEspUpdateAvail, false);
+ // LOGD("UPD cron %s", String(formattedTime));
+ printLogMsg("[UPD_CHK] cron " + String(formattedTime));
+
+ Cron.create(const_cast(formattedTime), checkUpdateAvail, false); // 0 0 */6 * * *
+ }
+ else
+ {
+ printLogMsg("[UPD_CHK] cron disabled");
+ }
if (systemCfg.nmEnable)
{
@@ -430,8 +669,8 @@ void setupCron()
char endCron[30];
strcpy(startCron, convertTimeToCron(String(systemCfg.nmStart)));
strcpy(endCron, convertTimeToCron(String(systemCfg.nmEnd)));
- LOGD("cron", "NM start %s", startCron);
- LOGD("cron", "NM end %s", endCron);
+ LOGD("[cron] NM start %s", const_cast(startCron));
+ LOGD("[cron] NM end %s", const_cast(endCron));
Cron.create(const_cast(startCron), nmActivate, false);
Cron.create(const_cast(endCron), nmDeactivate, false);
@@ -449,7 +688,7 @@ void setTimezone(String timezone)
String timeNow = asctime(&timeinfo);
timeNow.remove(timeNow.length() - 1);
- printLogMsg("Local time: " + timeNow);
+ printLogMsg("[Time] " + timeNow);
}
const char *getGmtOffsetForZone(const char *zone)
@@ -482,7 +721,7 @@ char *convertTimeToCron(const String &time)
static char formattedTime[16];
int hours, minutes;
- char timeArray[6];
+ char timeArray[6];
time.toCharArray(timeArray, sizeof(timeArray));
sscanf(timeArray, "%d:%d", &hours, &minutes);
@@ -500,7 +739,7 @@ ThisConfigStruct *findBrdConfig(int searchId = 0)
bool zbOk = false;
static ThisConfigStruct bestConfig;
- bestConfig.eth = {.addr = -1, .pwrPin = -1, .mdcPin = -1, .mdiPin = -1, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT, .pwrAltPin = -1};
+ bestConfig.eth = {.addr = -1, .pwrPin = -1, .mdcPin = -1, .mdiPin = -1, .phyType = ETH_PHY_LAN8720, .clkMode = ETH_CLOCK_GPIO17_OUT}; // .pwrAltPin = -1};
bestConfig.zb = {.txPin = -1, .rxPin = -1, .rstPin = -1, .bslPin = -1};
memset(&bestConfig.mist, -1, sizeof(bestConfig.mist));
strlcpy(bestConfig.board, "Unknown", sizeof(bestConfig.board));
@@ -513,95 +752,115 @@ ThisConfigStruct *findBrdConfig(int searchId = 0)
LOGI("Try brd: %d - %s", brdIdx, brdConfigs[brdIdx].board);
- if (brdIdx == 3) // T-Internet-POE
+ if (ethIdx == -1)
{
- pinMode(ethConfigs[ethIdx].pwrAltPin, OUTPUT);
- delay(50);
- digitalWrite(ethConfigs[ethIdx].pwrAltPin, LOW);
- delay(50);
- pinMode(ethConfigs[ethIdx].pwrAltPin, INPUT);
- delay(50);
- bool pwrPinState = digitalRead(ethConfigs[ethIdx].pwrAltPin);
- if (pwrPinState)
- {
- LOGW("%s", "Looks like not T-Internet-POE!");
- continue;
- }
- }
-
- if (ETH.begin(ethConfigs[ethIdx].addr, ethConfigs[ethIdx].pwrPin, ethConfigs[ethIdx].mdcPin, ethConfigs[ethIdx].mdiPin, ethConfigs[ethIdx].phyType, ethConfigs[ethIdx].clkMode, ethConfigs[ethIdx].pwrAltPin))
+ ethOk = true;
+ LOGD("NO ethernet OK: %d", ethIdx);
+ } // egin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE);
+
+#ifdef TASMOTA_PLATFORM
+ else if (ETH.begin(ethConfigs[ethIdx].phyType, ethConfigs[ethIdx].addr, ethConfigs[ethIdx].mdcPin, ethConfigs[ethIdx].mdiPin, ethConfigs[ethIdx].pwrPin, ethConfigs[ethIdx].clkMode)) // ethConfigs[ethIdx].pwrAltPin))
+#else
+ else if (ETH.begin(ethConfigs[ethIdx].addr, ethConfigs[ethIdx].pwrPin, ethConfigs[ethIdx].mdcPin, ethConfigs[ethIdx].mdiPin, ethConfigs[ethIdx].phyType, ethConfigs[ethIdx].clkMode)) // ethConfigs[ethIdx].pwrAltPin))
+#endif
{
ethOk = true;
- LOGD("Ethernet config OK: %d", ethIdx);
-
bestConfig.eth = ethConfigs[ethIdx];
+ LOGD("Ethernet config OK: %d", ethIdx);
+ }
- if (mistConfigs[mistIdx].btnPin > 0)
+ if (mistConfigs[mistIdx].btnPin > 0)
+ {
+ pinMode(mistConfigs[mistIdx].btnPin, INPUT);
+ int press = 0;
+ for (int y = 0; y < 10; y++)
{
- pinMode(mistConfigs[mistIdx].btnPin, INPUT);
- int press = 0;
- for (int y = 0; y < 10; y++)
+ int state = digitalRead(mistConfigs[mistIdx].btnPin);
+ if (state != mistConfigs[mistIdx].btnPlr)
{
- int state = digitalRead(mistConfigs[mistIdx].btnPin);
- if (state != mistConfigs[mistIdx].btnPlr)
- {
- press++;
- }
- delay(100);
+ press++;
}
- btnOk = (press <= 5);
+ delay(100);
+ }
+ btnOk = (press <= 5);
- if (!btnOk)
- {
- LOGD("Button pin ERROR");
- ethOk = false;
- }
- else
- {
- LOGD("Button pin OK");
- }
+ if (!btnOk)
+ {
+ LOGD("Button pin ERROR");
+ ethOk = false;
}
else
{
- btnOk = true;
+ LOGD("Button pin OK");
}
+ }
+ else
+ {
+ btnOk = true;
+ }
- if (btnOk)
- {
- LOGD("Trying Zigbee: %d", zbIdx);
- esp_task_wdt_reset();
- Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, zbConfigs[zbIdx].rxPin, zbConfigs[zbIdx].txPin);
+ if (btnOk)
+ {
+ LOGD("Trying Zigbee: %d", zbIdx);
+ esp_task_wdt_reset();
+ Serial2.begin(systemCfg.serialSpeed, SERIAL_8N1, zbConfigs[zbIdx].rxPin, zbConfigs[zbIdx].txPin);
- int BSL_PIN_MODE = 0;
- if (CCTool.begin(zbConfigs[zbIdx].rstPin, zbConfigs[zbIdx].bslPin, BSL_PIN_MODE))
+ int BSL_PIN_MODE = 0;
+ if (CCTool.begin(zbConfigs[zbIdx].rstPin, zbConfigs[zbIdx].bslPin, BSL_PIN_MODE))
+ {
+ if (CCTool.detectChipInfo())
{
- if (CCTool.detectChipInfo())
- {
- zbOk = true;
- LOGD("Zigbee config OK: %d", zbIdx);
+ zbOk = true;
+ LOGD("Zigbee config OK: %d", zbIdx);
+
+ bestConfig.zb = zbConfigs[zbIdx];
+ bestConfig.mist = mistConfigs[mistIdx];
- bestConfig.zb = zbConfigs[zbIdx];
- bestConfig.mist = mistConfigs[mistIdx];
- strlcpy(bestConfig.board, brdConfigs[brdIdx].board, sizeof(bestConfig.board));
- return &bestConfig;
+ bool multiCfg = false;
+ int brdNewId = -1;
+ for (int brdNewIdx = 0; brdNewIdx < BOARD_CFG_CNT; brdNewIdx++)
+ {
+ LOGD("%d %d", brdIdx, brdNewIdx);
+ if (brdIdx != brdNewIdx && brdConfigs[brdNewIdx].ethConfigIndex == ethIdx && brdConfigs[brdNewIdx].zbConfigIndex == zbIdx && brdConfigs[brdNewIdx].mistConfigIndex == mistIdx)
+ {
+ multiCfg = true;
+ brdNewId = brdNewIdx;
+ break;
+ }
+ }
+ const char *nameBrd;
+ if (!multiCfg)
+ {
+ nameBrd = brdConfigs[brdIdx].board;
+ strlcpy(bestConfig.board, nameBrd, sizeof(bestConfig.board));
}
else
{
- zbOk = false;
- LOGD("Zigbee config ERROR");
+ String nameBrdStr = ("Multi_" + String(brdNewId));
+ nameBrd = nameBrdStr.c_str();
+ // LOGW("%s", nameBrdStr);
+ strlcpy(bestConfig.board, nameBrd, sizeof(bestConfig.board));
}
+
+ return &bestConfig;
+ }
+ else
+ {
+ zbOk = false;
+ LOGD("Zigbee config ERROR");
}
}
}
LOGI("Config error with: %s", brdConfigs[brdIdx].board);
- DynamicJsonDocument config(300);
- config["searchId"] = brdIdx + 1;
- writeDefaultConfig(configFileHw, config);
+ // DynamicJsonDocument config(300);
+ // config["searchId"] = brdIdx + 1;
+ // writeDefaultConfig(configFileHw, config);
- LOGD("Restarting...");
- delay(500);
- ESP.restart();
+ snprintf(hwConfig.board, sizeof(hwConfig.board), "i%02d", brdIdx + 1);
+ saveHwConfig(hwConfig);
+
+ restartDevice();
return nullptr;
}
@@ -620,6 +879,7 @@ ThisConfigStruct *findBrdConfig(int searchId = 0)
void wgBegin()
{
+ // checkDNS();
if (!wg.is_initialized())
{
@@ -705,7 +965,8 @@ void wgLoop()
{
LOGD("Peer disconnect");
}
- vars.vpnWgPeerIp.clear();
+ // vars.vpnWgPeerIp.clear();
+ vars.vpnWgPeerIp.fromString("0.0.0.0");
vars.vpnWgConnect = false;
}
}
@@ -809,18 +1070,289 @@ void ledTask(void *parameter)
}
}
-void checkEspUpdateAvail()
+int compareVersions(String v1, String v2)
{
- String latestReleaseUrl = fetchGitHubReleaseInfo();
- String latestVersion = extractVersionFromURL(latestReleaseUrl);
+ int v1_major = v1.substring(0, v1.indexOf('.')).toInt();
+ int v2_major = v2.substring(0, v2.indexOf('.')).toInt();
- if (latestVersion.length() > 0 && latestVersion > VERSION)
+ if (v1_major != v2_major)
{
- vars.updateEspAvail = true;
+ return v1_major - v2_major;
+ }
+
+ String v1_suffix = v1.substring(v1.indexOf('.') + 1);
+ String v2_suffix = v2.substring(v2.indexOf('.') + 1);
+
+ if (v1_suffix.length() == 0)
+ return -1;
+ if (v2_suffix.length() == 0)
+ return 1;
+
+ return v1_suffix.compareTo(v2_suffix);
+}
+
+void checkUpdateAvail()
+{
+ if (!vars.apStarted)
+ {
+ const char *ESPkey = "ESP";
+ const char *ZBkey = "ZB";
+ const char *FoundKey = "Found ";
+ const char *NewFwKey = " new fw: ";
+ const char *TryKey = "try to install";
+ // String latestReleaseUrlEsp = fetchLatestEspFw();
+ String latestReleaseUrlZb = fetchLatestZbFw();
+
+ // String latestVersionEsp = extractVersionFromURL(latestReleaseUrlEsp);
+
+ FirmwareInfo esp_fw = fetchLatestEspFw();
+ String latestVersionEsp = esp_fw.version;
+ // String latestVersionEsp = "1.2.3";
+
+ String latestVersionZb = extractVersionFromURL(latestReleaseUrlZb);
+
+ strncpy(vars.lastESPVer, latestVersionEsp.c_str(), sizeof(vars.lastESPVer) - 1);
+ vars.lastESPVer[sizeof(vars.lastESPVer) - 1] = '\0';
+
+ LOGD("lastESPVer %s", vars.lastESPVer);
+
+ strncpy(vars.lastZBVer, latestVersionZb.c_str(), sizeof(vars.lastZBVer) - 1);
+ vars.lastZBVer[sizeof(vars.lastZBVer) - 1] = '\0';
+
+ LOGD("lastZBVer %s", vars.lastZBVer);
+
+ if (latestVersionEsp.length() > 0 && compareVersions(latestVersionEsp, VERSION) > 0)
+ {
+ vars.updateEspAvail = true;
+
+ printLogMsg(String(FoundKey) + String(ESPkey) + String(NewFwKey) + latestVersionEsp);
+ if (systemCfg.updAutoInst)
+ {
+ printLogMsg(String(TryKey));
+ // getEspUpdate(latestReleaseUrlEsp);
+ }
+ }
+ else
+ {
+ vars.updateEspAvail = false;
+ }
+
+ if (CCTool.chip.fwRev > 0 && latestVersionZb.length() > 0 && compareVersions(latestVersionZb, String(CCTool.chip.fwRev)) > 0)
+ {
+ vars.updateZbAvail = true;
+
+ printLogMsg(String(FoundKey) + String(ZBkey) + String(NewFwKey) + latestVersionZb);
+ if (systemCfg.updAutoInst)
+ {
+ printLogMsg(String(TryKey));
+ // flashZbUrl(latestReleaseUrlZb);
+ // restartDevice();
+ }
+ }
+ else
+ {
+ vars.updateZbAvail = false;
+ }
}
else
{
- vars.updateEspAvail = false;
+ LOGW("AP is started, skip update check");
}
- LOGD("%s", String(vars.updateEspAvail));
}
+
+bool isIpInSubnet(IPAddress ip, IPAddress subnetBase, IPAddress subnetMask)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if ((ip[i] & subnetMask[i]) != (subnetBase[i] & subnetMask[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool isValidIp(IPAddress ip)
+{
+ return ip != IPAddress(0, 0, 0, 0);
+}
+
+String getHostFromUrl(const String &url)
+{
+ int startIndex = url.indexOf("://") + 3;
+ int endIndex = url.indexOf('/', startIndex);
+ if (endIndex == -1)
+ {
+ endIndex = url.length();
+ }
+ return url.substring(startIndex, endIndex);
+}
+
+String getRadioRoleKey()
+{
+ String role;
+ switch (systemCfg.zbRole)
+ {
+ case COORDINATOR:
+ role = "coordinator";
+ break;
+ case ROUTER:
+ role = "router";
+ break;
+ case OPENTHREAD:
+ role = "thread";
+ break;
+ default:
+ role = "unknown";
+ break;
+ }
+ return role;
+}
+
+// Функция для удаления ведущих нулей из блока IPv6
+String removeLeadingZeros(const String &block)
+{
+ int i = 0;
+ while (i < block.length() - 1 && block[i] == '0')
+ {
+ i++;
+ }
+ return block.substring(i);
+}
+
+// Функция для сокращения IPv6-адреса
+String getShortenedIPv6(const String &ipv6)
+{
+ String result = "";
+ int start = 0;
+ int end = ipv6.indexOf(':');
+ bool zeroBlock = false;
+ bool inZeroBlock = false;
+
+ while (end != -1)
+ {
+ String block = ipv6.substring(start, end);
+ block = removeLeadingZeros(block);
+
+ if (block == "0")
+ {
+ if (!inZeroBlock)
+ {
+ if (zeroBlock)
+ {
+ result += ":";
+ }
+ result += ":";
+ inZeroBlock = true;
+ }
+ }
+ else
+ {
+ if (inZeroBlock)
+ {
+ inZeroBlock = false;
+ }
+ else if (zeroBlock)
+ {
+ result += ":";
+ }
+ result += block;
+ zeroBlock = true;
+ }
+
+ start = end + 1;
+ end = ipv6.indexOf(':', start);
+ }
+
+ // Обработка последнего блока
+ String block = ipv6.substring(start);
+ block = removeLeadingZeros(block);
+ if (block == "0")
+ {
+ if (!inZeroBlock)
+ {
+ if (zeroBlock)
+ {
+ result += ":";
+ }
+ result += ":";
+ }
+ }
+ else
+ {
+ if (inZeroBlock)
+ {
+ inZeroBlock = false;
+ }
+ else if (zeroBlock)
+ {
+ result += ":";
+ }
+ result += block;
+ }
+
+ // Удаление лишнего двоеточия в начале, если есть
+ if (result.startsWith("::") && result.length() > 2)
+ {
+ result = result.substring(1);
+ }
+
+ return result;
+}
+
+void restartDevice()
+{
+ LOGD("Restarting device...");
+ delay(100);
+ ESP.restart();
+}
+
+void freeHeapPrint()
+{
+ heap_caps_free(NULL);
+ size_t freeHeap = heap_caps_get_free_size(MALLOC_CAP_8BIT);
+ size_t minFreeHeap = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT);
+ LOGD("Free heap: %d, min free heap: %d", freeHeap, minFreeHeap);
+}
+
+bool dnsLookup(const String &url)
+{
+ IPAddress ip;
+ String host = getHostFromUrl(url);
+
+ // DNS lookup
+ if (!WiFi.hostByName(host.c_str(), ip))
+ {
+ printLogMsg("DNS lookup failed for host: " + host + ". Check your network connection and DNS settings.");
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void firstUpdCheck()
+{
+ int retryCount = 0;
+ int maxRetries = 3;
+ const int retryDelay = 500;
+ bool isSuccess = false;
+
+ while (retryCount < maxRetries && !isSuccess)
+ {
+ if (!dnsLookup("google.com"))
+ {
+ retryCount++;
+ printLogMsg("DNS lookup failed. Retrying...");
+ delay(retryDelay * 3);
+ }
+ else
+ {
+ isSuccess = true;
+ vars.firstUpdCheck = true;
+ checkUpdateAvail();
+ checkFileSys();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/etc.h b/src/etc.h
index 1b803a6a..9063bb9d 100644
--- a/src/etc.h
+++ b/src/etc.h
@@ -1,3 +1,8 @@
+#ifndef ETC_H
+#define ETC_H
+
+#include
+
#include
#include "const/hw.h"
@@ -5,6 +10,10 @@ void getReadableTime(String &readableTime, unsigned long beginTime);
String sha1(String payloadStr);
+int check1wire();
+void setup1wire(int pin);
+float get1wire();
+
extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT];
ThisConfigStruct *findBrdConfig(int searchId);
@@ -18,7 +27,7 @@ void zigbeeRestart();
void usbModeSet(usbMode mode);
void getDeviceID(char *arr);
-void writeDefaultConfig(const char *path, DynamicJsonDocument &doc);
+//void writeDefaultConfig(const char *path, DynamicJsonDocument &doc);
#define TIMEOUT_FACTORY_RESET 3
@@ -27,6 +36,7 @@ void factoryReset();
void setLedsDisable(bool all = false);
void cronTest();
void nmActivate();
+//bool checkDNS(bool setup = false);
void setupCron();
void setClock(void *pvParameters);
@@ -42,4 +52,23 @@ void hnBegin();
void ledTask(void *parameter);
String getTime();
-void checkEspUpdateAvail();
+void checkUpdateAvail();
+
+bool isIpInSubnet(IPAddress ip, IPAddress subnet, IPAddress subnetMask);
+bool isValidIp(IPAddress ip);
+String getHostFromUrl(const String& url);
+String getRadioRoleKey();
+String removeLeadingZeros(const String& block);
+String getShortenedIPv6(const String& ipv6);
+void restartDevice();
+void freeHeapPrint();
+bool dnsLookup(const String &url);
+void firstUpdCheck();
+
+struct FirmwareInfo {
+ String url;
+ String version;
+ String sha;
+};
+
+#endif // ETC_H
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index d4fbea65..8d776da9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -27,6 +27,7 @@
#include "version.h"
// #include "const/hw.h"
#include "per.h"
+#include "main.h"
#include "esp_system.h"
#include "esp_task_wdt.h"
@@ -54,15 +55,10 @@ extern int btnFlag;
bool updWeb = false;
-void mDNS_start();
-void connectWifi();
-// void handleLongBtn();
-void handleTmrNetworkOverseer();
-void setupCoordinatorMode();
-void startAP(const bool start);
-// void toggleUsbMode();
+int networkOverseerCounter = 0;
-Ticker tmrNetworkOverseer(handleTmrNetworkOverseer, overseerInterval, 0, MILLIS);
+// Ticker tmrNetworkOverseer(handleTmrNetworkOverseer, overseerInterval, 0, MILLIS);
+Ticker tmrNetworkOverseer;
IPAddress apIP(192, 168, 1, 1);
DNSServer dnsServer;
@@ -74,17 +70,25 @@ MDNSResponder mDNS;
void initLan()
{
- LOGD("Try to use %s", hwConfig.board);
-
- if (ETH.begin(hwConfig.eth.addr, hwConfig.eth.pwrPin, hwConfig.eth.mdcPin, hwConfig.eth.mdiPin, hwConfig.eth.phyType, hwConfig.eth.clkMode, hwConfig.eth.pwrAltPin))
+// ETH.begin(ethConfigs[ethIdx].phyType, ethConfigs[ethIdx].addr, ethConfigs[ethIdx].mdcPin, ethConfigs[ethIdx].mdiPin, ethConfigs[ethIdx].pwrPin, ethConfigs[ethIdx].clkMode)
+//
+#ifdef TASMOTA_PLATFORM
+ if (ETH.begin(hwConfig.eth.phyType, hwConfig.eth.addr, hwConfig.eth.mdcPin, hwConfig.eth.mdiPin, hwConfig.eth.pwrPin, hwConfig.eth.clkMode))
+#else
+ if (ETH.begin(hwConfig.eth.addr, hwConfig.eth.pwrPin, hwConfig.eth.mdcPin, hwConfig.eth.mdiPin, hwConfig.eth.phyType, hwConfig.eth.clkMode)) // hwConfig.eth.pwrAltPin))
+#endif
{
String modeString = networkCfg.ethDhcp ? "DHCP" : "Static";
- LOGD("LAN start ok, %s", modeString);
+ LOGD("LAN start ok, %s", modeString.c_str());
// ConfigSettings.disconnectEthTime = millis();
if (!networkCfg.ethDhcp)
{
+ LOGD("Static IP");
ETH.config(networkCfg.ethIp, networkCfg.ethGate, networkCfg.ethMask, networkCfg.ethDns1, networkCfg.ethDns2);
}
+ ETH.enableIpV6();
+ // ETH.enableIPv6();
+ // ETH.printTo(Serial);
}
else
{
@@ -123,14 +127,15 @@ void startServers(bool usb = false)
startAP(false);
- if (!vars.apStarted)
+ /*if (!vars.apStarted)
{
if (vpnCfg.wgEnable)
{
wgBegin();
}
- }
+ }*/
+ mDNS_start();
/* //not available now
if (vpnCfg.hnEnable)
{
@@ -141,28 +146,38 @@ void startServers(bool usb = false)
void handleTmrNetworkOverseer()
{
- switch (systemCfg.workMode)
+ // switch (systemCfg.workMode)
+ //{
+ // case WORK_MODE_NETWORK:
+ networkOverseerCounter++;
+ if (!networkCfg.wifiEnable && !networkCfg.ethEnable)
{
- case WORK_MODE_NETWORK:
- if (!networkCfg.wifiEnable && !networkCfg.ethEnable)
+ if (!vars.apStarted)
{
LOGD("Both interfaces disabled. Start AP");
startAP(true);
connectWifi();
}
- if (networkCfg.wifiEnable)
- {
- LOGD("WiFi.status = %s", String(WiFi.status()));
+ }
+ if (networkCfg.wifiEnable)
+ {
+ LOGD("WiFi.status = %s", String(WiFi.status()).c_str());
- if (WiFi.isConnected())
+ if (WiFi.isConnected())
+ {
+ LOGD("WIFI CONNECTED");
+ // tmrNetworkOverseer.stop();
+ tmrNetworkOverseer.detach();
+ if (!vars.firstUpdCheck)
{
- LOGD("WIFI CONNECTED");
- mDNS_start();
- tmrNetworkOverseer.stop();
+ firstUpdCheck();
}
- else
+ }
+ else
+ {
+ if (!vars.zbFlashing)
{
- if (tmrNetworkOverseer.counter() > overseerMaxRetry)
+ if (networkOverseerCounter > overseerMaxRetry)
{
LOGD("WIFI counter overflow");
startAP(true);
@@ -170,31 +185,41 @@ void handleTmrNetworkOverseer()
}
}
}
- if (networkCfg.ethEnable)
+ }
+ if (networkCfg.ethEnable)
+ {
+ if (vars.connectedEther)
{
- if (vars.connectedEther)
+ LOGD("LAN CONNECTED");
+ // tmrNetworkOverseer.stop();
+ tmrNetworkOverseer.detach();
+ if (vars.apStarted)
{
- LOGD("LAN CONNECTED");
- mDNS_start();
- tmrNetworkOverseer.stop();
+ startAP(false);
}
- else
+ if (!vars.firstUpdCheck)
{
- if (tmrNetworkOverseer.counter() > overseerMaxRetry)
- {
- LOGD("LAN counter overflow");
- startAP(true);
- }
+ firstUpdCheck();
}
}
- break;
- case WORK_MODE_USB:
+ else
+ {
+ // if (tmrNetworkOverseer.counter() > overseerMaxRetry)
+ if (networkOverseerCounter > overseerMaxRetry)
+ {
+ LOGD("LAN counter overflow!");
+ startAP(true);
+ }
+ }
+ }
+ // break;
+ /*case WORK_MODE_USB:
if (tmrNetworkOverseer.counter() > 3)
{ // 10 seconds for wifi connect
if (WiFi.isConnected())
{
tmrNetworkOverseer.stop();
- startServers(true);
+ // startServers(true);
}
else
{
@@ -204,7 +229,7 @@ void handleTmrNetworkOverseer()
if (vars.connectedEther)
{
tmrNetworkOverseer.stop();
- startServers(true);
+ // startServers(true);
}
else
{ // no network interfaces
@@ -216,15 +241,15 @@ void handleTmrNetworkOverseer()
}
break;
default:
- break;
- }
+ break;*/
+ //}
}
void NetworkEvent(WiFiEvent_t event)
{
const char *wifiKey = "WiFi";
const char *ethKey = "ETH";
-
+ // esp_err_t result5;
switch (event)
{
case ARDUINO_EVENT_ETH_START: // 18: // SYSTEM_EVENT_ETH_START:
@@ -236,49 +261,92 @@ void NetworkEvent(WiFiEvent_t event)
LOGD("%s Connected", ethKey);
break;
case ARDUINO_EVENT_ETH_GOT_IP: // 22: // SYSTEM_EVENT_ETH_GOT_IP:
- startServers();
- LOGI("%s MAC: %s, IP: %s, Mask: %s, Gw: %s, %dMbps", ethKey,
+ // startServers();
+ LOGI("%s MAC: %s, IP: %s, Mask: %s, Gw: %s, DNS: %s, %dMbps", ethKey,
ETH.macAddress().c_str(),
ETH.localIP().toString().c_str(),
ETH.subnetMask().toString().c_str(),
ETH.gatewayIP().toString().c_str(),
+ ETH.dnsIP().toString().c_str(),
ETH.linkSpeed());
vars.connectedEther = true;
- // ConfigSettings.disconnectEthTime = 0;
+ // checkDNS(true);
+ // ConfigSettings.disconnectEthTime = 0;
break;
+
+ case ARDUINO_EVENT_ETH_GOT_IP6:
+ LOGI("ETH IPv6 %s", ETH.localIPv6().toString().c_str());
+ vars.connectedEther = true;
+ vars.ethIPv6 = true;
+ break;
+
case ARDUINO_EVENT_ETH_DISCONNECTED: // 21: //SYSTEM_EVENT_ETH_DISCONNECTED:
LOGD("%s Disconnected", ethKey);
vars.connectedEther = false;
+ vars.ethIPv6 = false;
// ConfigSettings.disconnectEthTime = millis();
- if (tmrNetworkOverseer.state() == STOPPED && systemCfg.workMode == WORK_MODE_NETWORK)
+ // if (tmrNetworkOverseer.state() == STOPPED) //&& systemCfg.workMode == WORK_MODE_NETWORK)
+ if (!tmrNetworkOverseer.active())
{
- tmrNetworkOverseer.start();
+ // tmrNetworkOverseer.start();
+ tmrNetworkOverseer.attach(overseerInterval, handleTmrNetworkOverseer);
}
break;
- case SYSTEM_EVENT_ETH_STOP: // 27:
+ case 27: // case SYSTEM_EVENT_ETH_STOP: // 27:
case ARDUINO_EVENT_ETH_STOP:
LOGD("%s Stopped", ethKey);
vars.connectedEther = false;
// ConfigSettings.disconnectEthTime = millis();
- if (tmrNetworkOverseer.state() == STOPPED)
+ // if (tmrNetworkOverseer.state() == STOPPED)
+ if (!tmrNetworkOverseer.active())
{
- tmrNetworkOverseer.start();
+ // tmrNetworkOverseer.start();
+ tmrNetworkOverseer.attach(overseerInterval, handleTmrNetworkOverseer);
}
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP: // SYSTEM_EVENT_STA_GOT_IP:
- startServers();
- LOGI("%s MAC: %s, IP: %s, Mask: %s, Gw: %s", wifiKey,
+ // startServers();
+ LOGI("%s MAC: %s, IP: %s, Mask: %s, Gw: %s, DNS: %s", wifiKey,
WiFi.macAddress().c_str(),
WiFi.localIP().toString().c_str(),
WiFi.subnetMask().toString().c_str(),
- WiFi.gatewayIP().toString().c_str());
+ WiFi.gatewayIP().toString().c_str(),
+ WiFi.dnsIP().toString().c_str());
+ // checkDNS(true);
+ LOGD("WiFi TX %s", String(WiFi.getTxPower()).c_str());
+
+ /*result5 = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+ if (result5 == ESP_OK)
+ {
+ Serial.println("Wi-Fi protocol set successfully.");
+ }
+ else
+ {
+ Serial.printf("Error setting Wi-Fi protocol: %d\n", result5);
+ }
+
+ uint8_t cur_mode;
+ esp_wifi_get_protocol(WIFI_IF_STA, &cur_mode);
+ Serial.print("Current Wi-Fi protocol: ");
+ if (cur_mode & WIFI_PROTOCOL_11B)
+ Serial.print("802.11b ");
+ if (cur_mode & WIFI_PROTOCOL_11G)
+ Serial.print("802.11g ");
+ if (cur_mode & WIFI_PROTOCOL_11N)
+ Serial.print("802.11n ");
+ Serial.println();*/
+ break;
+ case ARDUINO_EVENT_WIFI_STA_GOT_IP6: // SYSTEM_EVENT_STA_GOT_IP6:
+ LOGI("WiFi IPv6 %s", WiFi.localIPv6().toString().c_str());
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: // SYSTEM_EVENT_STA_DISCONNECTED:
LOGD("%s STA DISCONNECTED", wifiKey);
- if (tmrNetworkOverseer.state() == STOPPED)
+ // if (tmrNetworkOverseer.state() == STOPPED)
+ if (!tmrNetworkOverseer.active())
{
- tmrNetworkOverseer.start();
+ // tmrNetworkOverseer.start();
+ tmrNetworkOverseer.attach(overseerInterval, handleTmrNetworkOverseer);
}
break;
default:
@@ -289,7 +357,7 @@ void NetworkEvent(WiFiEvent_t event)
void startAP(const bool start)
{
String tag = "sAP";
- LOGD("begin s=%d, v=%d", start, vars.apStarted);
+ LOGD("begin cmd=%d, state=%d", start, vars.apStarted);
if (vars.apStarted)
{
@@ -316,19 +384,26 @@ void startAP(const bool start)
WiFi.disconnect();
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
WiFi.softAP(vars.deviceId); //, WIFIPASS);
-
+
// if DNSServer is started with "*" for domain name, it will reply with
// provided IP to all DNS request
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", apIP);
WiFi.setSleep(false);
// ConfigSettings.wifiAPenblTime = millis();
- LOGD("startServers()");
+ // LOGD("startServers()");
startServers();
vars.apStarted = true;
}
}
+void stopWifi()
+{
+ LOGD("stopWifi");
+ WiFi.disconnect();
+ WiFi.mode(WIFI_OFF);
+}
+
void connectWifi()
{
static uint8_t timeout = 0;
@@ -344,14 +419,36 @@ void connectWifi()
LOGD("timeout");
}
WiFi.persistent(false);
- esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B);
+
+ // Dont work on Arduino framework
+
+ /*uint8_t cur_mode;
+ esp_wifi_get_protocol(WIFI_IF_STA, &cur_mode);
+ Serial.print("wifi mode ");
+ String result = "";
+ result += String(cur_mode, DEC);
+ Serial.println(result);
+
+ esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); // networkCfg.wifiMode); // WIFI_PROTOCOL_11B | ); //
+
+ Serial.print("wifi mode setup ");
+ esp_err_t result2 = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+ Serial.println(result2);
+
+ cur_mode = -1;
+ esp_wifi_get_protocol(WIFI_IF_STA, &cur_mode);
+ Serial.print("wifi mode ");
+ result = "";
+ result += String(cur_mode, DEC);
+ Serial.println(result);*/
+
if ((strlen(networkCfg.wifiSsid) >= 2) && (strlen(networkCfg.wifiPass) >= 8))
{
LOGD("Ok SSID & PASS");
if (vars.apStarted)
{
- // LOGD("WiFi.mode(WIFI_AP_STA)");
- // WiFi.mode(WIFI_AP_STA);
+ LOGD("WiFi.mode(WIFI_AP_STA)");
+ WiFi.mode(WIFI_AP_STA);
}
else
{
@@ -373,31 +470,104 @@ void connectWifi()
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
LOGD("Try DHCP");
}
- WiFi.begin(networkCfg.wifiSsid, networkCfg.wifiPass);
- LOGD("WiFi.begin");
- }
- else
- {
- if (!(systemCfg.workMode == WORK_MODE_USB && systemCfg.keepWeb))
- { // dont start ap in keepWeb
- LOGD("NO SSID & PASS ");
- if (!vars.connectedEther)
+ WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
+ WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL);
+
+ WiFi.setAutoReconnect(true);
+
+ // Dont work on Arduino framework
+ /*uint8_t wifiProtocols = WIFI_PROTOCOL_LR;
+
+ uint8_t currentProtocols;
+ esp_err_t resultGetProt = esp_wifi_get_protocol(WIFI_IF_STA, ¤tProtocols);
+ if (resultGetProt == ESP_OK)
+ {
+ Serial.printf("Current WiFi protocols: 0x%X\n", currentProtocols);
+ }
+ else
+ {
+ Serial.printf("Failed to get current WiFi protocols: 0x%X\n", resultGetProt);
+ }
+
+ // Объединение текущих и желаемых настроек протоколов
+ uint8_t newProtocols = wifiProtocols;
+
+ // Установка новых протоколов WiFi перед началом подключения
+ esp_err_t resultWifiProtSet = esp_wifi_set_protocol(WIFI_IF_STA, newProtocols);
+ if (resultWifiProtSet == ESP_OK)
+ {
+ Serial.println("WiFi protocols set successfully");
+ resultGetProt = esp_wifi_get_protocol(WIFI_IF_STA, ¤tProtocols);
+ if (resultGetProt == ESP_OK)
{
- LOGD("and problem with LAN");
- startAP(true);
- LOGD("so setupWifiAP");
+ Serial.printf("Current WiFi protocols: 0x%X\n", currentProtocols);
}
else
{
- LOGD("but LAN is OK");
+ Serial.printf("Failed to get current WiFi protocols: 0x%X\n", resultGetProt);
}
}
+ else
+ {
+ Serial.printf("Failed to set WiFi protocols: 0x%X\n", resultWifiProtSet);
+ if (resultWifiProtSet == ESP_ERR_WIFI_NOT_INIT)
+ {
+ Serial.println("WiFi is not initialized by esp_wifi_init");
+ }
+ else if (resultWifiProtSet == ESP_ERR_WIFI_IF)
+ {
+ Serial.println("Invalid interface");
+ }
+ else if (resultWifiProtSet == ESP_ERR_INVALID_ARG)
+ {
+ Serial.println("Invalid argument");
+ }
+ else
+ {
+ Serial.println("Unknown error");
+ }
+ }
+ */
+
+ WiFi.begin(networkCfg.wifiSsid, networkCfg.wifiPass);
+ WiFi.setTxPower(networkCfg.wifiPower);
+ WiFi.enableIpV6();
+ // LOGD("WiFi TX %s", String(WiFi.getTxPower()).c_str());
+
+ /*esp_err_t result = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+ if (result == ESP_OK)
+ {
+ Serial.println("Wi-Fi protocol set successfully.");
+ }
+ else
+ {
+ Serial.printf("Error setting Wi-Fi protocol: %d\n", result);
+ }*/
+ LOGD("WiFi.begin");
+ }
+ else
+ {
+ // if (!(systemCfg.workMode == WORK_MODE_USB && systemCfg.keepWeb))
+ //{ // dont start ap in keepWeb
+ LOGD("NO SSID & PASS ");
+ if (!vars.connectedEther)
+ {
+ LOGD("and problem with LAN");
+ startAP(true);
+ LOGD("so setupWifiAP");
+ }
+ else
+ {
+ LOGD("but LAN is OK");
+ }
+ // }
}
}
void mDNS_start()
{
- const char *host = "_xzg";
+ const char *names[] = {"_xzg", "_zigbee-gateway", "_zigstar_gw"};
+
const char *http = "_http";
const char *tcp = "_tcp";
if (!mDNS.begin(systemCfg.hostname))
@@ -406,19 +576,48 @@ void mDNS_start()
}
else
{
- LOGI("mDNS responder started on %s.local", String(systemCfg.hostname));
+ LOGI("mDNS responder started on %s.local", String(systemCfg.hostname).c_str());
//----- WEB ------
mDNS.addService(http, tcp, 80);
//--zeroconf zha--
- mDNS.addService(host, tcp, systemCfg.socketPort);
- mDNS.addServiceTxt(host, tcp, "version", "1.0");
- mDNS.addServiceTxt(host, tcp, "radio_type", "znp");
- mDNS.addServiceTxt(host, tcp, "baud_rate", String(systemCfg.serialSpeed));
- mDNS.addServiceTxt(host, tcp, "data_flow_control", "software");
- mDNS.addServiceTxt(host, tcp, "board", String(hwConfig.board));
+ for (int i = 0; i < sizeof(names) / sizeof(names[0]); i++)
+ {
+ mDNS.addService(names[i], tcp, systemCfg.socketPort);
+ mDNS.addServiceTxt(names[i], tcp, "version", "1.0");
+ mDNS.addServiceTxt(names[i], tcp, "radio_type", "znp");
+ mDNS.addServiceTxt(names[i], tcp, "serial_number", String(CCTool.chip.ieee));
+ mDNS.addServiceTxt(names[i], tcp, "baud_rate", String(systemCfg.serialSpeed));
+ mDNS.addServiceTxt(names[i], tcp, "data_flow_control", "software");
+ mDNS.addServiceTxt(names[i], tcp, "board", String(hwConfig.board));
+ }
}
}
+void networkStart()
+{
+ // if ((systemCfg.workMode != WORK_MODE_USB) || systemCfg.keepWeb)
+ //{ // start network overseer
+ // if (tmrNetworkOverseer.state() == STOPPED)
+ if (!tmrNetworkOverseer.active())
+ {
+ // tmrNetworkOverseer.start();
+ tmrNetworkOverseer.attach(overseerInterval, handleTmrNetworkOverseer);
+ }
+ WiFi.onEvent(NetworkEvent);
+ if (networkCfg.ethEnable)
+ initLan();
+ if (networkCfg.wifiEnable)
+ connectWifi();
+ //}
+
+ // if (!systemCfg.disableWeb && ((systemCfg.workMode != WORK_MODE_USB) || systemCfg.keepWeb))
+ // updWeb = true; // handle web server
+ if (!systemCfg.disableWeb)
+ updWeb = true; // handle web server
+ // if (systemCfg.workMode == WORK_MODE_USB && systemCfg.keepWeb)
+ // connectWifi(); // try 2 connect wifi
+}
+
void setupCoordinatorMode()
{
if (systemCfg.workMode > 2 || systemCfg.workMode < 0)
@@ -428,46 +627,85 @@ void setupCoordinatorMode()
}
String workModeString = systemCfg.workMode ? "USB" : "Network";
- LOGI("%s", workModeString);
-
- if ((systemCfg.workMode != WORK_MODE_USB) || systemCfg.keepWeb)
- { // start network overseer
- if (tmrNetworkOverseer.state() == STOPPED)
- {
- tmrNetworkOverseer.start();
- }
- WiFi.onEvent(NetworkEvent);
- if (networkCfg.ethEnable)
- initLan();
- if (networkCfg.wifiEnable)
- connectWifi();
- }
+ LOGI("%s", workModeString.c_str());
switch (systemCfg.workMode)
{
case WORK_MODE_USB:
ledControl.modeLED.mode = LED_ON;
- delay(500);
+ delay(100);
usbModeSet(ZIGBEE);
+ startServers(true);
break;
case WORK_MODE_NETWORK:
ledControl.powerLED.mode = LED_BLINK_1Hz;
+ delay(100);
+ usbModeSet(XZG);
+ startServers();
break;
default:
break;
}
+}
- if (!systemCfg.disableWeb && ((systemCfg.workMode != WORK_MODE_USB) || systemCfg.keepWeb))
- updWeb = true; // handle web server
- if (systemCfg.workMode == WORK_MODE_USB && systemCfg.keepWeb)
- connectWifi(); // try 2 connect wifi
+void getEspUpdateTask(void *pvParameters)
+{
+ TaskParams *params = static_cast(pvParameters);
+ LOGI("getEspUpdateTask %s", params->url);
+ getEspUpdate(params->url);
+ vTaskDelete(NULL);
+}
+
+void timerCallback(TimerHandle_t xTimer)
+{
+ TaskParams *params = static_cast(pvTimerGetTimerID(xTimer));
+ xTaskCreate(getEspUpdateTask, "getEspUpdateTask", 8192, params, 1, NULL);
+}
+
+void checkFileSys()
+{
+ FirmwareInfo fwInfo = fetchLatestEspFw("fs");
+ File commitFile = LittleFS.open("/x/commit", "r");
+ if (!commitFile)
+ {
+ LOGI("Commit file not found");
+ vars.needFsDownload = true;
+ }
+ else
+ {
+ String gitSha = fwInfo.sha.substring(0, 7);
+ String fileSha = commitFile.readString().substring(0, 7).c_str();
+
+ LOGI("Commit file found: Git: %s, File: %s", gitSha.c_str(), fileSha.c_str());
+
+ if (gitSha.length() == 7 && gitSha != fileSha)
+ {
+ LOGI("Found new FS commit");
+ vars.needFsDownload = true;
+ }
+ commitFile.close();
+ }
+
+ if (vars.needFsDownload)
+ {
+ LOGI("Downloading FS");
+
+ static String urlString = fwInfo.url;
+ static TaskParams params = {urlString.c_str()};
+
+ TimerHandle_t timer = xTimerCreate("StartTaskTimer", pdMS_TO_TICKS(5000), pdFALSE, ¶ms, timerCallback);
+ if (timer != NULL)
+ {
+ xTimerStart(timer, 0);
+ }
+ }
}
void setup()
{
Serial.begin(115200); // todo ifdef DEBUG
- String tag = "SETUP";
+ // String tag = "SETUP";
initNVS();
@@ -479,32 +717,79 @@ void setup()
loadMqttConfig(mqttCfg);
// LOAD System vars and create FS / start
- if (!LittleFS.begin(FORMAT_LITTLEFS_IF_FAILED, "/lfs2", 10))
+ if (!LittleFS.begin(false, "/lfs2", 10))
{
- LOGD("Error with LITTLEFS");
- return;
+ LOGD("Error with FS - try to download");
+ vars.needFsDownload = true;
+ // return;
}
- // LOAD System vars and create FS / end
+ loadHwConfig(hwConfig);
+ if (String(hwConfig.board).length() < 4)
+ {
+ LOGD("No HW config in NVS. Try to load from file");
+ if (!loadFileConfigHW())
+ {
+ int searchId = 0;
+ if (hwConfig.board[0] == 'i')
+ {
+ // Проверка, что второй и третий символы являются цифрами
+ if (isdigit(hwConfig.board[1]) && isdigit(hwConfig.board[2]))
+ {
+ searchId = (hwConfig.board[1] - '0') * 10 + (hwConfig.board[2] - '0');
+ }
+ else
+ {
+ LOGD("Invalid board ID format: %s", hwConfig.board);
+ }
+ }
+ LOGD("hwConfig.board: %s", hwConfig.board);
+ LOGD("searchId: %d", searchId);
+ ThisConfigStruct *newConfig = findBrdConfig(searchId);
+ if (newConfig)
+ {
+ LOGD("Find. Saving config");
+ saveHwConfig(*newConfig);
+
+ if (!newConfig->eth.mdcPin == -1 && !newConfig->eth.mdiPin == -1)
+ {
+ networkCfg.ethEnable = true;
+ saveNetworkConfig(networkCfg);
+ }
- // READ file to support migrate from old firmware
- loadFileSystemVar();
- loadFileConfigSerial();
- loadFileConfigWifi();
- loadFileConfigEther();
- loadFileConfigGeneral();
- loadFileConfigSecurity();
- loadFileConfigMqtt();
- loadFileConfigWg();
- // READ file to support migrate from old firmware
+ LOGD("Calc and save temp offset");
+ float CPUtemp = getCPUtemp(true);
+ int offset = CPUtemp - 30;
+ systemCfg.tempOffset = int(offset);
+ saveSystemConfig(systemCfg);
+
+ restartDevice();
+ }
+ }
+ }
- // String cfg = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg, &vars);
- // LOGD("After READ OLD config\n %s", cfg.c_str());
+ if (hwConfig.eth.mdcPin == -1 || hwConfig.eth.mdiPin == -1)
+ {
+ if (networkCfg.ethEnable)
+ {
+ networkCfg.ethEnable = false;
+ saveNetworkConfig(networkCfg);
+ }
+ }
- loadFileConfigHW();
+ String cfg = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg, NULL, NULL);
+ LOGI("\n%s", cfg.c_str());
vars.apStarted = false;
+ networkStart();
+
+ /*while (WiFi.status() != WL_CONNECTED && !vars.connectedEther)
+ {
+ delay(1000);
+ LOGD("Wait for network");
+ }*/
+
// AVOID USING PIN 0
if (hwConfig.mist.btnPin > 0)
{
@@ -524,8 +809,10 @@ void setup()
if (hwConfig.mist.uartSelPin > 0)
{
pinMode(hwConfig.mist.uartSelPin, OUTPUT);
- vars.hwUartSelIs = true;
- usbModeSet(XZG);
+ // vars.hwUartSelIs = true;
+ // usbModeSet(XZG);
+ bool fixState = (hwConfig.mist.uartSelPlr == 1) ? LOW : HIGH;
+ digitalWrite(hwConfig.mist.uartSelPin, fixState);
}
if ((hwConfig.zb.txPin > 0) && (hwConfig.zb.rxPin > 0) && (hwConfig.zb.rstPin > 0) && (hwConfig.zb.bslPin > 0))
@@ -543,24 +830,43 @@ void setup()
buttonSetup();
}
- String cfg = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg);
- LOGD("Config:\n%s", cfg.c_str());
-
- cfg = makeJsonConfig(NULL, NULL, NULL, NULL, &vars);
- LOGI("VARS:\n%s", cfg.c_str());
-
setLedsDisable(); // with setup ?? // move to vars ?
- setupCoordinatorMode();
vars.connectedClients = 0;
- xTaskCreate(updateWebTask, "update Web Task", 2048, NULL, 7, NULL);
+ xTaskCreate(updateWebTask, "update Web Task", 8192, NULL, 8, NULL);
printNVSFreeSpace();
- zbFwCheck();
+ if (systemCfg.zbRole == COORDINATOR || systemCfg.zbRole == UNDEFINED)
+ {
+ /*if (zbFwCheck())
+ {
+ if (systemCfg.zbRole == UNDEFINED)
+ {
+ systemCfg.zbRole = COORDINATOR;
+ saveSystemConfig(systemCfg);
+ }
+ }*/
+ zbFwCheck();
+ LOGI("[RCP] FW: %s", String(CCTool.chip.fwRev).c_str());
+ }
+ else
+ {
+ LOGI("[RCP] role: %s", String(systemCfg.zbRole).c_str());
+ }
+ LOGI("[ESP] FW: %s", String(VERSION).c_str());
+
+ // LOGI("Load cfg %s", hwConfig.board);
- LOGD("done");
+ setupCoordinatorMode();
+
+ setup1wire(check1wire());
+
+ cfg = makeJsonConfig(NULL, NULL, NULL, NULL, &vars, NULL);
+ LOGI("\n%s", cfg.c_str());
+
+ LOGI("done");
}
WiFiClient client[10];
@@ -599,7 +905,7 @@ void socketClientDisconnected(int client)
void printRecvSocket(size_t bytes_read, uint8_t net_buf[BUFFER_SIZE])
{
- char output_sprintf[2];
+ char output_sprintf[3];
if (bytes_read > 0)
{
String tmpTime;
@@ -629,7 +935,7 @@ void printRecvSocket(size_t bytes_read, uint8_t net_buf[BUFFER_SIZE])
void printSendSocket(size_t bytes_read, uint8_t serial_buf[BUFFER_SIZE])
{
- char output_sprintf[2];
+ char output_sprintf[3];
String tmpTime;
String buff = "";
unsigned long timeLog = millis();
@@ -667,7 +973,7 @@ void loop(void)
buttonLoop();
}
- tmrNetworkOverseer.update();
+ // tmrNetworkOverseer.update();
if (updWeb)
{
webServerHandleClient();
@@ -680,102 +986,128 @@ void loop(void)
}
}
- if (systemCfg.workMode != WORK_MODE_USB)
+ if (!vars.zbFlashing)
{
- uint16_t net_bytes_read = 0;
- uint8_t net_buf[BUFFER_SIZE];
- uint16_t serial_bytes_read = 0;
- uint8_t serial_buf[BUFFER_SIZE];
- if (server.hasClient())
+ if (systemCfg.workMode == WORK_MODE_USB)
+ {
+ if (Serial2.available())
+ {
+ Serial.write(Serial2.read());
+ Serial.flush();
+ }
+ if (Serial.available())
+ {
+ Serial2.write(Serial.read());
+ Serial2.flush();
+ }
+ return;
+ }
+
+ else if (systemCfg.workMode == WORK_MODE_NETWORK)
{
- for (byte i = 0; i < MAX_SOCKET_CLIENTS; i++)
+ uint16_t net_bytes_read = 0;
+ uint8_t net_buf[BUFFER_SIZE];
+ uint16_t serial_bytes_read = 0;
+ uint8_t serial_buf[BUFFER_SIZE];
+
+ if (server.hasClient())
{
- if (!client[i] || !client[i].connected())
+ for (byte i = 0; i < MAX_SOCKET_CLIENTS; i++)
{
- if (client[i])
- {
- client[i].stop();
- }
- if (systemCfg.fwEnabled)
+ if (!client[i] || !client[i].connected())
{
- WiFiClient TempClient2 = server.available();
- if (TempClient2.remoteIP() == systemCfg.fwIp)
+ if (client[i])
{
- printLogMsg(String("[SOCK IP WHITELIST] Accepted connection from IP: ") + TempClient2.remoteIP().toString());
- client[i] = TempClient2;
- continue;
+ client[i].stop();
+ }
+ if (systemCfg.fwEnabled)
+ {
+ if (server.hasClient())
+ {
+ WiFiClient TempClient2 = server.available();
+ IPAddress clientIp = TempClient2.remoteIP();
+
+ if (isValidIp(clientIp) && isIpInSubnet(clientIp, systemCfg.fwIp, systemCfg.fwMask))
+ {
+ printLogMsg(String("[SOCK IP FW] Accepted from IP: ") + clientIp.toString());
+ client[i] = TempClient2;
+ // TempClient2.stop();
+ continue;
+ }
+ else
+ {
+ printLogMsg(String("[SOCK IP FW] Rejected from IP: ") + clientIp.toString());
+ // TempClient2.stop();
+ }
+ }
}
else
{
- printLogMsg(String("[SOCK IP WHITELIST] Rejected connection from unknown IP: ") + TempClient2.remoteIP().toString());
+ client[i] = server.available();
+ continue;
}
}
- else
- {
- client[i] = server.available();
- continue;
- }
}
+ WiFiClient TempClient = server.available();
+ TempClient.stop();
}
- WiFiClient TempClient = server.available();
- TempClient.stop();
- }
- for (byte cln = 0; cln < MAX_SOCKET_CLIENTS; cln++)
- {
- if (client[cln])
+ for (byte cln = 0; cln < MAX_SOCKET_CLIENTS; cln++)
{
- socketClientConnected(cln, client[cln].remoteIP());
- while (client[cln].available())
- { // read from LAN
- net_buf[net_bytes_read] = client[cln].read();
- if (net_bytes_read < BUFFER_SIZE - 1)
- net_bytes_read++;
- } // send to Zigbee
- Serial2.write(net_buf, net_bytes_read);
- // print to web console
- printRecvSocket(net_bytes_read, net_buf);
- net_bytes_read = 0;
+ if (client[cln])
+ {
+ socketClientConnected(cln, client[cln].remoteIP());
+ while (client[cln].available())
+ { // read from LAN
+ net_buf[net_bytes_read] = client[cln].read();
+ if (net_bytes_read < BUFFER_SIZE - 1)
+ net_bytes_read++;
+ } // send to Zigbee
+ Serial2.write(net_buf, net_bytes_read);
+ // print to web console
+ printRecvSocket(net_bytes_read, net_buf);
+ net_bytes_read = 0;
+ }
+ else
+ {
+ socketClientDisconnected(cln);
+ }
}
- else
+
+ if (Serial2.available())
{
- socketClientDisconnected(cln);
+ while (Serial2.available())
+ { // read from Zigbee
+ serial_buf[serial_bytes_read] = Serial2.read();
+ if (serial_bytes_read < BUFFER_SIZE - 1)
+ serial_bytes_read++;
+ }
+ // send to LAN
+ for (byte cln = 0; cln < MAX_SOCKET_CLIENTS; cln++)
+ {
+ if (client[cln])
+ client[cln].write(serial_buf, serial_bytes_read);
+ }
+ // print to web console
+ printSendSocket(serial_bytes_read, serial_buf);
+ serial_bytes_read = 0;
}
- }
- if (Serial2.available())
- {
- while (Serial2.available())
- { // read from Zigbee
- serial_buf[serial_bytes_read] = Serial2.read();
- if (serial_bytes_read < BUFFER_SIZE - 1)
- serial_bytes_read++;
- }
- // send to LAN
- for (byte cln = 0; cln < MAX_SOCKET_CLIENTS; cln++)
+ /*if (mqttCfg.enable)
{
- if (client[cln])
- client[cln].write(serial_buf, serial_bytes_read);
- }
- // print to web console
- printSendSocket(serial_bytes_read, serial_buf);
- serial_bytes_read = 0;
+ // mqttLoop();
+ }*/
}
-
- /*if (mqttCfg.enable)
+ if (vpnCfg.wgEnable && vars.vpnWgInit)
{
- // mqttLoop();
- }*/
- }
- if (vpnCfg.wgEnable && vars.vpnWgInit)
- {
- wgLoop();
- }
+ wgLoop();
+ }
- if (WiFi.getMode() == WIFI_MODE_AP || WiFi.getMode() == WIFI_MODE_APSTA)
- {
- dnsServer.processNextRequest();
+ if (WiFi.getMode() == WIFI_MODE_AP || WiFi.getMode() == WIFI_MODE_APSTA)
+ {
+ dnsServer.processNextRequest();
+ }
+ Cron.delay();
}
- Cron.delay();
}
diff --git a/src/main.h b/src/main.h
new file mode 100644
index 00000000..847ff61c
--- /dev/null
+++ b/src/main.h
@@ -0,0 +1,24 @@
+#ifndef MAIN_H
+#define MAIN_H
+
+void mDNS_start();
+
+void connectWifi();
+// void handleLongBtn();
+void handleTmrNetworkOverseer();
+void setupCoordinatorMode();
+void startAP(const bool start);
+
+// void toggleUsbMode();
+
+
+void stopWifi();
+void checkFileSys();
+
+struct TaskParams
+{
+ const char *url;
+};
+
+
+#endif // MAIN_H
\ No newline at end of file
diff --git a/src/mqtt.cpp b/src/mqtt.cpp
index bf30cb4f..d7b3c9ef 100644
--- a/src/mqtt.cpp
+++ b/src/mqtt.cpp
@@ -30,9 +30,12 @@ TimerHandle_t mqttPubStateTimer;
const char *homeAssistant = "homeassistant";
const char *haSensor = "sensor";
+const char *haUpdate = "update";
const char *haButton = "button";
const char *haBinarySensor = "binary_sensor";
const char *willMessage = "offline"; // to do
+const char *haUpdateLogoUrl = "https://xzg.xyzroe.cc/assets/images/logo.svg";
+const char *haUpdateAttrTemplate = "{\"in_progress\": {{ value_json['state'] }} }";
const char *availabilityTopic = "/avty";
const char *configTopic = "/config";
@@ -55,21 +58,28 @@ String getUptime()
return readableTime;
}
-String getTemperature()
+String getStrCpuTemp()
{
float CPUtemp = getCPUtemp();
return String(CPUtemp);
}
+String getStr1wTemp()
+{
+ float temp = get1wire();
+ return String(temp);
+}
+
String getWlanIp()
{
return networkCfg.wifiDhcp ? WiFi.localIP().toString() : networkCfg.wifiIp.toString();
}
String getWlanSsid()
-{
+{
String ssid = WiFi.SSID();
- if (ssid.isEmpty()) {
+ if (ssid.isEmpty())
+ {
ssid = "-";
}
return ssid;
@@ -97,7 +107,16 @@ String getConnections()
String getZigbeeFWver()
{
- return String(CCTool.chip.fwRev);
+ String fw;
+ if (CCTool.chip.fwRev > 0)
+ {
+ fw = CCTool.chip.fwRev;
+ }
+ else
+ {
+ fw = systemCfg.zbFw;
+ }
+ return fw;
}
String getZigbeeHWrev()
@@ -119,67 +138,108 @@ String getWorkMode()
return "Error";
}
+/*
+String getRole()
+{
+ String role;
+ switch (systemCfg.zbRole)
+ {
+ case COORDINATOR:
+ role = "Coordinator";
+ break;
+ case ROUTER:
+ role = "Router";
+ break;
+ case OPENTHREAD:
+ role = "Thread";
+ break;
+ default:
+ role = "Unknown";
+ break;
+ }
+ return role;
+}
+*/
+
+String getRole()
+{
+ String role = getRadioRoleKey();
+ if (role.length() > 0)
+ {
+ role[0] = role[0] == ' ' ? role[0] : role[0] - 32;
+ }
+ return role;
+}
+
+const char *rst_esp = "rst_esp";
+const char *rst_zig = "rst_zig";
+const char *enbl_bsl = "enbl_bsl";
+const char *io = "/io/";
+const char *cmd = "/cmd";
+const char *upd_esp = "upd_esp";
+const char *upd_zb = "upd_zb";
+const char *upd_esp_slash = "/upd/esp";
+const char *upd_zb_slash = "/upd/zb";
+const char *mdiPrefix = "mdi:";
+const char *coolant_temperature = "coolant-temperature";
+const char *access_point = "access-point";
+const char *temperature = "temperature";
+const char *diagnostic = "diagnostic";
+const char *config = "config";
+const char *restart = "restart";
+
mqttTopicsConfig mqttTopicsConfigs[] = {
{.name = "Restart ESP",
.sensorType = haButton,
- .sensorId = "rst_esp",
- .stateTopic = "/io/rst_esp",
- .commandTopic = "/cmd",
- .icon = "mdi:restore-alert",
- .payloadPress = "{cmd:\"rst_esp\"}",
- .deviceClass = "restart"},
+ .sensorId = rst_esp,
+ .stateTopic = String(io) + rst_esp,
+ .commandTopic = cmd,
+ .icon = String(mdiPrefix) + "restore-alert",
+ .payloadPress = rst_esp,
+ .deviceClass = restart},
{.name = "Restart Zigbee",
.sensorType = haButton,
- .sensorId = "rst_zig",
- .stateTopic = "/io/rst_zig",
- .commandTopic = "/cmd",
- .icon = "mdi:restart",
- .payloadPress = "{cmd:\"rst_zig\"}",
- .deviceClass = "restart"},
+ .sensorId = rst_zig,
+ .stateTopic = String(io) + rst_zig,
+ .commandTopic = cmd,
+ .icon = String(mdiPrefix) + restart,
+ .payloadPress = rst_zig,
+ .deviceClass = restart},
{.name = "Enable BSL",
.sensorType = haButton,
- .sensorId = "enbl_bsl",
- .stateTopic = "/io/enbl_bsl",
- .commandTopic = "/cmd",
+ .sensorId = enbl_bsl,
+ .stateTopic = String(io) + enbl_bsl,
+ .commandTopic = cmd,
.icon = "mdi:flash",
- .payloadPress = "{cmd:\"enbl_bsl\"}",
+ .payloadPress = enbl_bsl,
.deviceClass = "identify"},
{.name = "Socket",
.sensorType = haBinarySensor,
.sensorId = "socket",
.stateTopic = "/io/socket",
.deviceClass = "connectivity"},
- {.name = "Update ESP32",
- .sensorType = haBinarySensor,
- .sensorId = "update_esp",
- .stateTopic = "/io/update_esp",
- .deviceClass = "update"},
{.name = "Uptime",
.sensorType = haSensor,
.sensorId = "uptime",
.stateTopic = stateTopic,
- .icon = "mdi:clock",
- .valueTemplate = "{{ value_json.uptime }}",
+ .icon = String(mdiPrefix) + "clock",
.getSensorValue = getUptime},
{.name = "WLAN IP",
.sensorType = haSensor,
.sensorId = "wlanIp",
.stateTopic = stateTopic,
- .icon = "mdi:wifi-check",
- .valueTemplate = "{{ value_json.wlanIp }}",
+ .icon = String(mdiPrefix) + "wifi-check",
.getSensorValue = getWlanIp},
{.name = "WLAN SSID",
.sensorType = haSensor,
.sensorId = "wlanSsid",
.stateTopic = stateTopic,
- .icon = "mdi:wifi-marker",
- .valueTemplate = "{{ value_json.wlanSsid }}",
+ .icon = String(mdiPrefix) + "wifi-marker",
.getSensorValue = getWlanSsid},
{.name = "WLAN RSSI",
.sensorType = haSensor,
.sensorId = "wlanRssi",
.stateTopic = stateTopic,
- .valueTemplate = "{{ value_json.wlanRssi }}",
.deviceClass = "signal_strength",
.unitOfMeasurement = "dBm",
.getSensorValue = getWlanRssi},
@@ -187,120 +247,220 @@ mqttTopicsConfig mqttTopicsConfigs[] = {
.sensorType = haSensor,
.sensorId = "lanIp",
.stateTopic = stateTopic,
- .icon = "mdi:check-network",
- .valueTemplate = "{{ value_json.lanIp }}",
+ .icon = String(mdiPrefix) + "check-network",
.getSensorValue = getLanIp},
{.name = "ESP Temperature",
.sensorType = haSensor,
- .sensorId = "temperature",
+ .sensorId = temperature,
+ .stateTopic = stateTopic,
+ .icon = String(mdiPrefix) + coolant_temperature,
+ .deviceClass = temperature,
+ .unitOfMeasurement = "°C",
+ .getSensorValue = getStrCpuTemp},
+ {.name = "1W Temperature",
+ .sensorType = haSensor,
+ .sensorId = "temperature1w",
.stateTopic = stateTopic,
- .icon = "mdi:coolant-temperature",
- .valueTemplate = "{{ value_json.temperature }}",
- .deviceClass = "temperature",
+ .icon = String(mdiPrefix) + coolant_temperature,
+ .deviceClass = temperature,
.unitOfMeasurement = "°C",
- .getSensorValue = getTemperature},
+ .getSensorValue = getStr1wTemp},
{.name = "Hostname",
.sensorType = haSensor,
.sensorId = "hostname",
.stateTopic = stateTopic,
- .icon = "mdi:account-network",
- .valueTemplate = "{{ value_json.hostname }}",
+ .icon = String(mdiPrefix) + "account-network",
.getSensorValue = getHostname},
{.name = "Socket Connections",
.sensorType = haSensor,
.sensorId = "connections",
.stateTopic = stateTopic,
- .icon = "mdi:check-network-outline",
- .valueTemplate = "{{ value_json.connections }}",
+ .icon = String(mdiPrefix) + "check-network-outline",
.getSensorValue = getConnections},
{.name = "Mode",
.sensorType = haSensor,
.sensorId = "mode",
.stateTopic = stateTopic,
- .icon = "mdi:access-point-network",
- .valueTemplate = "{{ value_json.mode }}",
+ .icon = String(mdiPrefix) + access_point + "-network",
.deviceClass = "enum",
+ .entityCategory = diagnostic,
.getSensorValue = getWorkMode},
- {.name = "Zigbee FW version",
+ {.name = "Radio chip",
.sensorType = haSensor,
- .sensorId = "zbfw",
+ .sensorId = "zbhw",
.stateTopic = stateTopic,
- .icon = "mdi:access-point",
- .valueTemplate = "{{ value_json.zbfw }}",
- .getSensorValue = getZigbeeFWver},
- {.name = "Zigbee HW revision",
+ .icon = String(mdiPrefix) + access_point,
+ .entityCategory = diagnostic,
+ .getSensorValue = getZigbeeHWrev},
+ {.name = "Zigbee Role",
.sensorType = haSensor,
- .sensorId = "zbhw",
+ .sensorId = "zbrl",
.stateTopic = stateTopic,
- .icon = "mdi:access-point",
- .valueTemplate = "{{ value_json.zbhw }}",
- .getSensorValue = getZigbeeHWrev}};
+ .icon = String(mdiPrefix) + access_point,
+ .entityCategory = diagnostic,
+ .getSensorValue = getRole},
+ {.name = "ESP32 firmware",
+ .sensorType = haUpdate,
+ .sensorId = upd_esp,
+ .stateTopic = upd_esp_slash,
+ .commandTopic = cmd,
+ .entityCategory = config,
+ .entityPicture = haUpdateLogoUrl,
+ .payloadInstall = upd_esp,
+ //.releaseUrl = "zb_upd",
+ .jsonAttrTemplate = haUpdateAttrTemplate,
+ .jsonAttrTopic = upd_esp_slash},
+ {.name = "Radio firmware",
+ .sensorType = haUpdate,
+ .sensorId = upd_zb,
+ .stateTopic = upd_zb_slash,
+ .commandTopic = cmd,
+ .entityCategory = config,
+ .entityPicture = haUpdateLogoUrl,
+ .payloadInstall = upd_zb,
+ //.releaseUrl = "zb_upd",
+ .jsonAttrTemplate = haUpdateAttrTemplate,
+ .jsonAttrTopic = upd_zb_slash}};
+
+/*{.name = "Zigbee FW version",
+.sensorType = haSensor,
+.sensorId = "zbfw",
+.stateTopic = stateTopic,
+.icon = "mdi:access-point",
+.valueTemplate = "{{ value_json.zbfw }}",
+.getSensorValue = getZigbeeFWver},*/
void mqttConnectSetup()
{
LOGD("mqttConnectSetup");
-
- if (mqttCfg.reconnectInt == 0)
- {
- mqttCfg.reconnectInt = 30;
- LOGI("Reconnect Int didn't set. So use %d seconds", mqttCfg.reconnectInt);
- }
- if (mqttCfg.updateInt == 0)
+ if (true) // checkDNS())
{
- mqttCfg.updateInt = 60;
- LOGI("Update Int didn't set. So use %d seconds", mqttCfg.updateInt);
- }
- mqttReconnectTimer = xTimerCreate("mqttReconnectTimer", pdMS_TO_TICKS(mqttCfg.reconnectInt * 1000), pdFALSE, (void *)0, reinterpret_cast(connectToMqtt));
- mqttPubStateTimer = xTimerCreate("mqttPubStateTimer", pdMS_TO_TICKS(mqttCfg.updateInt * 1000), pdFALSE, (void *)0, reinterpret_cast(mqttPublishState));
+ if (mqttCfg.reconnectInt == 0)
+ {
+ mqttCfg.reconnectInt = 30;
+ LOGD("Reconnect Int didn't set. So use %d seconds", mqttCfg.reconnectInt);
+ }
+ if (mqttCfg.updateInt == 0)
+ {
+ mqttCfg.updateInt = 60;
+ LOGD("Update Int didn't set. So use %d seconds", mqttCfg.updateInt);
+ }
+ mqttReconnectTimer = xTimerCreate("mqttReconnectTimer", pdMS_TO_TICKS(mqttCfg.reconnectInt * 1000), pdFALSE, (void *)0, reinterpret_cast(connectToMqtt));
+ mqttPubStateTimer = xTimerCreate("mqttPubStateTimer", pdMS_TO_TICKS(mqttCfg.updateInt * 1000), pdFALSE, (void *)0, reinterpret_cast(mqttPublishState));
- if (mqttReconnectTimer == NULL)
- {
- LOGD("Failed to create mqttReconnectTimer");
- }
+ if (mqttReconnectTimer == NULL)
+ {
+ LOGD("Failed to create mqttReconnectTimer");
+ }
- if (mqttPubStateTimer == NULL)
- {
- LOGD("Failed to create mqttPubStateTimer");
- }
+ if (mqttPubStateTimer == NULL)
+ {
+ LOGD("Failed to create mqttPubStateTimer");
+ }
- uint16_t keepAlive = mqttCfg.updateInt + 10;
- mqttClient.setKeepAlive(keepAlive);
+ uint16_t keepAlive = mqttCfg.updateInt + 10;
+ mqttClient.setKeepAlive(keepAlive);
- const char* clientId = vars.deviceId;
- mqttClient.setClientId(clientId);
+ const char *clientId = vars.deviceId;
+ mqttClient.setClientId(clientId);
- mqttClient.setCredentials(mqttCfg.user, mqttCfg.pass);
+ mqttClient.setCredentials(mqttCfg.user, mqttCfg.pass);
- //String topic = String(mqttCfg.topic) + "/avty";
- //mqttClient.setWill(topic.c_str(), 1, true, "offline");
+ // String topic = String(mqttCfg.topic) + "/avty";
+ // mqttClient.setWill(topic.c_str(), 1, true, "offline");
- mqttClient.setServer(mqttCfg.server, mqttCfg.port);
+ mqttClient.setServer(mqttCfg.server, mqttCfg.port);
-/* NO SSL SUPPORT in current SDK
-#if ASYNC_TCP_SSL_ENABLED
- mqttClient.setSecure(MQTT_SECURE);
- if (MQTT_SECURE)
- {
- mqttClient.addServerFingerprint((const uint8_t[])MQTT_SERVER_FINGERPRINT);
+ /* NO SSL SUPPORT in current SDK
+ #if ASYNC_TCP_SSL_ENABLED
+ mqttClient.setSecure(MQTT_SECURE);
+ if (MQTT_SECURE)
+ {
+ mqttClient.addServerFingerprint((const uint8_t[])MQTT_SERVER_FINGERPRINT);
+ }
+ #endif
+ */
+
+ mqttClient.onConnect(onMqttConnect);
+ mqttClient.onDisconnect(onMqttDisconnect);
+
+ mqttClient.onMessage(onMqttMessage);
+
+ connectToMqtt();
+ /*if (xTimerStart(mqttReconnectTimer, 0) != pdPASS)
+ {
+ LOGD("Failed to start timer");
+ }*/
}
-#endif
-*/
+}
- mqttClient.onConnect(onMqttConnect);
- mqttClient.onDisconnect(onMqttDisconnect);
+void mqttDisconnectCleanup()
+{
+ LOGD("mqttDisconnectCleanup");
- mqttClient.onMessage(onMqttMessage);
+ // Остановить и удалить таймеры
+ if (mqttReconnectTimer != NULL)
+ {
+ if (xTimerStop(mqttReconnectTimer, 0) == pdPASS)
+ {
+ if (xTimerDelete(mqttReconnectTimer, 0) == pdPASS)
+ {
+ mqttReconnectTimer = NULL;
+ LOGD("mqttReconnectTimer stopped and deleted");
+ }
+ else
+ {
+ LOGD("Failed to delete mqttReconnectTimer");
+ }
+ }
+ else
+ {
+ LOGD("Failed to stop mqttReconnectTimer");
+ }
+ }
+
+ if (mqttPubStateTimer != NULL)
+ {
+ if (xTimerStop(mqttPubStateTimer, 0) == pdPASS)
+ {
+ if (xTimerDelete(mqttPubStateTimer, 0) == pdPASS)
+ {
+ mqttPubStateTimer = NULL;
+ LOGD("mqttPubStateTimer stopped and deleted");
+ }
+ else
+ {
+ LOGD("Failed to delete mqttPubStateTimer");
+ }
+ }
+ else
+ {
+ LOGD("Failed to stop mqttPubStateTimer");
+ }
+ }
- if (xTimerStart(mqttReconnectTimer, 0) != pdPASS)
+ // Отключить MQTT-клиент
+ if (mqttClient.connected())
{
- LOGD("Failed to start timer");
+ mqttClient.disconnect();
+ LOGD("MQTT client disconnected");
}
+
+ // Очистить любые другие ресурсы, если необходимо
+ // Например, очистить буферы, закрыть соединения и т.д.
}
void connectToMqtt()
{
- LOGD("Connecting to MQTT...");
- mqttClient.connect();
+ if (!vars.zbFlashing)
+ {
+ LOGD("Connecting...");
+ mqttClient.connect();
+ }
+ else
+ {
+ LOGD("only after ZB flash");
+ }
}
void onMqttConnect(bool sessionPresent)
@@ -311,16 +471,22 @@ void onMqttConnect(bool sessionPresent)
vars.mqttConn = true;
- mqttPublishDiscovery();
+ if (mqttCfg.discovery)
+ {
+ mqttPublishDiscovery();
+ }
mqttPublishIo("rst_esp", 0);
mqttPublishIo("rst_zig", 0);
mqttPublishIo("enbl_bsl", 0);
- bool socket_state = vars.connectedClients ? 1 : 0;
- mqttPublishIo("socket", socket_state);
- mqttPublishIo("update_esp", vars.updateEspAvail);
+ mqttPublishIo("socket", vars.connectedClients ? 1 : 0);
+ // mqttPublishIo("update_esp", vars.updateEspAvail);
+ // mqttPublishIo("update_zb", vars.updateZbAvail);
mqttPublishState();
+ mqttPublishUpdate("esp");
+ mqttPublishUpdate("zb");
+
mqttPublishAvail();
}
@@ -330,29 +496,42 @@ void onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
vars.mqttConn = false;
- xTimerStart(mqttReconnectTimer, 0);
+ if (!vars.zbFlashing)
+ {
+ xTimerStart(mqttReconnectTimer, 0);
+ }
}
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
{
+ static char json[512];
+ // static DynamicJsonDocument doc(512);
+
String topicStr(topic);
if (topicStr.endsWith("/cmd"))
{
- char json[len + 1];
- memcpy(json, payload, len);
- json[len] = '\0';
-
- DynamicJsonDocument doc(512);
- deserializeJson(doc, json);
- const char *command = doc["cmd"];
+ if (len < sizeof(json))
+ {
+ memcpy(json, payload, len);
+ json[len] = '\0';
- LOGD("cmd - %s", String(json));
+ LOGD("json - %s", String(json));
- if (command)
+ if (strlen(json) > 0)
+ {
+ executeCommand(json);
+ }
+ else
+ {
+ LOGD("empty cmnd");
+ }
+ }
+ else
{
- executeCommand(command);
+ LOGW("cmnd too large");
}
}
+ topicStr.clear();
}
void executeCommand(const char *command)
@@ -361,7 +540,7 @@ void executeCommand(const char *command)
if (strcmp(command, "rst_esp") == 0)
{
printLogMsg("ESP restart MQTT");
- ESP.restart();
+ restartDevice();
}
if (strcmp(command, "rst_zig") == 0)
@@ -375,6 +554,20 @@ void executeCommand(const char *command)
printLogMsg("Zigbee BSL enable MQTT");
zigbeeEnableBSL();
}
+
+ if (strcmp(command, "upd_esp") == 0)
+ {
+ mqttPublishUpdate("esp", true);
+ printLogMsg("Going to update ESP");
+ // to - do
+ }
+
+ if (strcmp(command, "upd_zb") == 0)
+ {
+ mqttPublishUpdate("zb", true);
+ printLogMsg("Going to update ESP");
+ // to - do
+ }
}
void mqttPublishAvail()
@@ -394,36 +587,97 @@ void mqttPublishIo(const String &io, bool st)
}
}
+void mqttPublishUpdate(const String &chip, bool instState)
+{
+ // String state = st ? "ON" : "OFF";
+ if (mqttClient.connected())
+ {
+ /*
+ String topic = String(mqttCfg.topic) + "/io/" + io;
+ LOGD("Pub Io %s at %s", state.c_str(), topic.c_str());
+ mqttClient.publish(topic.c_str(), 0, true, state.c_str());*/
+ static DynamicJsonDocument jsonBuff(256);
+ static String mqttBuffer;
+ char verArr[25];
+ const char *env = STRINGIFY(BUILD_ENV_NAME);
+
+ const char *installed_version = "installed_version";
+ const char *latest_version = "latest_version";
+ const char *state = "state";
+
+ if (chip == "esp")
+ {
+ sprintf(verArr, "%s (%s)", VERSION, env);
+ jsonBuff[installed_version] = String(verArr);
+ jsonBuff[latest_version] = String(vars.lastESPVer);
+ jsonBuff[state] = int(instState);
+ }
+ else if (chip == "zb")
+ {
+ jsonBuff[installed_version] = String(getZigbeeFWver());
+ jsonBuff[latest_version] = String(vars.lastZBVer);
+ jsonBuff[state] = int(instState);
+ }
+
+ String topic = String(mqttCfg.topic) + "/upd/" + chip;
+ LOGD("Pub upd %s at %s", chip, topic.c_str());
+
+ serializeJson(jsonBuff, mqttBuffer);
+
+ mqttClient.publish(topic.c_str(), 1, true, mqttBuffer.c_str());
+ jsonBuff.clear();
+ mqttBuffer.clear();
+ }
+}
+
void mqttPublishState()
{
- DynamicJsonDocument buffJson(512);
- for (const auto &item : mqttTopicsConfigs)
+ if (!vars.zbFlashing)
{
- if (item.getSensorValue != nullptr)
+ static DynamicJsonDocument buffJson(512);
+ static String mqttBuffer;
+
+ buffJson.clear();
+ for (const auto &item : mqttTopicsConfigs)
{
- String sensorValue = item.getSensorValue();
- if (sensorValue.length() > 0)
+ if (item.sensorId != "temperature1w" || vars.oneWireIs)
{
- buffJson[item.sensorId] = sensorValue;
+ if (item.getSensorValue != nullptr)
+ {
+ String sensorValue = item.getSensorValue();
+ if (sensorValue.length() > 0)
+ {
+ buffJson[item.sensorId] = sensorValue;
+ }
+ }
}
}
- }
- String topic = mqttCfg.topic + String(stateTopic);
- String mqttBuffer;
- serializeJson(buffJson, mqttBuffer);
+ String topic = mqttCfg.topic + String(stateTopic);
+ serializeJson(buffJson, mqttBuffer);
- LOGD("%s", mqttBuffer.c_str());
+ LOGD("%s", mqttBuffer.c_str());
- mqttClient.publish(topic.c_str(), 0, true, mqttBuffer.c_str());
+ mqttClient.publish(topic.c_str(), 0, true, mqttBuffer.c_str());
+ topic.clear();
+ mqttBuffer.clear();
+ }
+ else
+ {
+ LOGD("only after ZB flash");
+ }
xTimerStart(mqttPubStateTimer, 0);
}
void mqttPublishDiscovery()
{
- DynamicJsonDocument devInfo(256);
+ static DynamicJsonDocument devInfo(256);
+ static DynamicJsonDocument buffJson(2048);
+ static String mqttBuffer;
+
+ devInfo.clear();
devInfo["ids"] = vars.deviceId;
- devInfo["name"] = systemCfg.hostname;
+ devInfo["name"] = systemCfg.hostname; // mqttCfg.topic;
devInfo["mf"] = "XZG";
devInfo["mdl"] = hwConfig.board;
char verArr[25];
@@ -431,50 +685,76 @@ void mqttPublishDiscovery()
sprintf(verArr, "%s (%s)", VERSION, env);
devInfo["sw"] = String(verArr);
- DynamicJsonDocument buffJson(2048);
- String mqttBuffer;
-
+ buffJson.clear();
for (const auto &item : mqttTopicsConfigs)
{
- buffJson["dev"] = devInfo;
- buffJson["name"] = item.name;
- buffJson["uniq_id"] = String(mqttCfg.topic) + "/" + item.sensorId;
- buffJson["stat_t"] = mqttCfg.topic + item.stateTopic;
- buffJson["avty_t"] = mqttCfg.topic + String(availabilityTopic);
- if (!String(item.commandTopic).isEmpty())
+ if (item.sensorId != "temperature1w" || vars.oneWireIs)
{
- buffJson["cmd_t"] = mqttCfg.topic + item.commandTopic;
- }
+ buffJson["dev"] = devInfo;
+ buffJson["name"] = item.name;
+ buffJson["uniq_id"] = String(vars.deviceId) + "_" + item.sensorId;
+ buffJson["stat_t"] = mqttCfg.topic + item.stateTopic;
+ buffJson["avty_t"] = mqttCfg.topic + String(availabilityTopic);
+ if (!String(item.commandTopic).isEmpty())
+ {
+ buffJson["cmd_t"] = mqttCfg.topic + item.commandTopic;
+ }
- if (!String(item.icon).isEmpty())
- {
- buffJson["icon"] = item.icon;
- }
- if (!String(item.payloadPress).isEmpty())
- {
- buffJson["payload_press"] = item.payloadPress;
- }
- if (!String(item.valueTemplate).isEmpty())
- {
- buffJson["val_tpl"] = item.valueTemplate;
- }
- if (!String(item.jsonAttributeTopic).isEmpty())
- {
- buffJson["json_attr_t"] = mqttCfg.topic + item.jsonAttributeTopic;
- }
- if (!String(item.deviceClass).isEmpty())
- {
- buffJson["dev_cla"] = item.deviceClass;
- }
- if (!String(item.unitOfMeasurement).isEmpty())
- {
- buffJson["unit_of_meas"] = item.unitOfMeasurement;
- }
+ if (!String(item.icon).isEmpty())
+ {
+ buffJson["ic"] = item.icon;
+ }
+ if (!String(item.payloadPress).isEmpty())
+ {
+ buffJson["pl_prs"] = item.payloadPress;
+ }
+ if (item.sensorType == haSensor)
+ {
+ buffJson["val_tpl"] = "{{ value_json." + item.sensorId + " }}";
+ }
+ if (!String(item.deviceClass).isEmpty())
+ {
+ buffJson["dev_cla"] = item.deviceClass;
+ }
+ if (!String(item.unitOfMeasurement).isEmpty())
+ {
+ buffJson["unit_of_meas"] = item.unitOfMeasurement;
+ }
+ if (!String(item.entityCategory).isEmpty())
+ {
+ buffJson["ent_cat"] = item.entityCategory;
+ }
+ if (!String(item.entityPicture).isEmpty())
+ {
+ buffJson["ent_pic"] = item.entityPicture;
+ }
+ if (!String(item.payloadInstall).isEmpty())
+ {
+ buffJson["pl_inst"] = item.payloadInstall;
+ }
+ if (!String(item.releaseUrl).isEmpty())
+ {
+ buffJson["rel_u"] = item.releaseUrl;
+ }
+ if (!String(item.jsonAttrTemplate).isEmpty())
+ {
+ buffJson["json_attr_tpl"] = item.jsonAttrTemplate;
+ }
+ if (!String(item.jsonAttrTopic).isEmpty())
+ {
+ buffJson["json_attr_t"] = mqttCfg.topic + item.jsonAttrTopic;
+ }
- String topic = String(homeAssistant) + "/" + item.sensorType + "/" + mqttCfg.topic + "/" + item.sensorId + configTopic;
- serializeJson(buffJson, mqttBuffer);
- mqttClient.publish(topic.c_str(), 1, true, mqttBuffer.c_str());
- buffJson.clear();
- mqttBuffer.clear();
+ String topic = String(homeAssistant) + "/" + item.sensorType + "/" + mqttCfg.topic + "/" + item.sensorId + configTopic;
+ serializeJson(buffJson, mqttBuffer);
+ LOGD("%s at %s", mqttBuffer.c_str(), topic.c_str());
+ mqttClient.publish(topic.c_str(), 1, true, mqttBuffer.c_str());
+ buffJson.clear();
+ mqttBuffer.clear();
+ }
}
+
+ devInfo.clear();
+ buffJson.clear();
+ mqttBuffer.clear();
}
\ No newline at end of file
diff --git a/src/mqtt.h b/src/mqtt.h
index 745648e2..09beeddc 100644
--- a/src/mqtt.h
+++ b/src/mqtt.h
@@ -2,6 +2,7 @@
#include
void mqttConnectSetup();
+void mqttDisconnectCleanup();
void connectToMqtt();
void onMqttConnect(bool sessionPresent);
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
@@ -9,6 +10,7 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
void executeCommand(const char *command);
void mqttPublishAvail();
void mqttPublishIo(const String &io, bool st);
+void mqttPublishUpdate(const String &chip, bool state = false);
void mqttPublishState();
void mqttPublishDiscovery();
@@ -23,8 +25,13 @@ struct mqttTopicsConfig {
String icon;
String payloadPress;
String valueTemplate;
- String jsonAttributeTopic;
String deviceClass;
String unitOfMeasurement;
+ String entityCategory;
+ String entityPicture;
+ String payloadInstall;
+ String releaseUrl;
+ String jsonAttrTemplate;
+ String jsonAttrTopic;
SensorValueFunction getSensorValue;
};
\ No newline at end of file
diff --git a/src/per.cpp b/src/per.cpp
index 8f0fded8..824c837a 100644
--- a/src/per.cpp
+++ b/src/per.cpp
@@ -40,7 +40,10 @@ extern CCTools CCTool;
// extern int btnFlag;
int btnFlag = 0;
-Ticker tmrBtnLongPress(handleLongBtn, 1000, 0, MILLIS);
+#include
+
+//Ticker tmrBtnLongPress(handleLongBtn, 1000, 0, MILLIS);
+Ticker tmrBtnLongPress; // Объявление объекта Ticker без параметров
void handleLongBtn()
{
@@ -71,7 +74,8 @@ void handleLongBtn()
setLedsDisable(!vars.disableLeds);
vars.disableLeds = !vars.disableLeds;
}
- tmrBtnLongPress.stop();
+ //tmrBtnLongPress.stop();
+ tmrBtnLongPress.detach(); // Использование метода detach() вместо stop()
btnFlag = false;
}
if (btnFlag >= 5)
@@ -79,7 +83,8 @@ void handleLongBtn()
ledControl.modeLED.mode = LED_FLASH_3Hz;
printLogMsg("BTN - 5sec - zigbeeEnableBSL");
zigbeeEnableBSL();
- tmrBtnLongPress.stop();
+ //tmrBtnLongPress.stop();
+ tmrBtnLongPress.detach(); // Использование метода detach() вместо stop()
btnFlag = false;
}
}
@@ -95,13 +100,13 @@ void toggleUsbMode()
systemCfg.workMode = WORK_MODE_NETWORK;
}
saveSystemConfig(systemCfg);
- LOGD("Change mode to %s", String(systemCfg.workMode));
+ LOGD("Change mode to %s", String(systemCfg.workMode).c_str());
if (vars.hwLedUsbIs)
{
ledControl.modeLED.mode = LED_ON;
}
- ESP.restart();
+ restartDevice();
}
void buttonInit()
@@ -148,12 +153,14 @@ void buttonLoop()
{
if (digitalRead(hwConfig.mist.btnPin) != hwConfig.mist.btnPlr) // pressed
{
- if (tmrBtnLongPress.state() == STOPPED)
+ //if (tmrBtnLongPress.state() == STOPPED)
+ if (!tmrBtnLongPress.active()) // Проверка активности таймера с помощью метода active()
{
- tmrBtnLongPress.start();
+ //tmrBtnLongPress.start();
+ tmrBtnLongPress.attach(1, handleLongBtn); // Запуск таймера с интервалом 1 секунда и функцией обратного вызова handleLongBtn
}
}
- tmrBtnLongPress.update();
+ //tmrBtnLongPress.update();
}
IRAM_ATTR bool debounce()
@@ -190,7 +197,7 @@ void ledModeSetup()
LOGD("%d", ledControl.modeLED.mode);
- xTaskCreate(ledTask, "MODE LED Task", 2048, &ledControl.modeLED, 6, NULL);
+ xTaskCreate(ledTask, "MODE LED Task", 2048, &ledControl.modeLED, 7, NULL);
}
void ledPwrSetup()
diff --git a/src/version.h b/src/version.h
index aa76c0fe..5f23cfb8 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,4 +1,4 @@
// AUTO GENERATED FILE
#ifndef VERSION
- #define VERSION "20240526"
+ #define VERSION "20241001"
#endif
diff --git a/src/web.cpp b/src/web.cpp
index 56d51c19..cbf1854d 100644
--- a/src/web.cpp
+++ b/src/web.cpp
@@ -2,7 +2,7 @@
#include
#include
#include
-#include
+// #include
#include
#include
#include
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include "config.h"
#include "web.h"
@@ -20,6 +21,7 @@
#include "const/keys.h"
// #include "const/hw.h"
+/*
#include "webh/html/PAGE_VPN.html.gz.h"
#include "webh/html/PAGE_MQTT.html.gz.h"
#include "webh/html/PAGE_ABOUT.html.gz.h"
@@ -31,18 +33,21 @@
#include "webh/html/PAGE_TOOLS.html.gz.h"
#include "webh/html/PAGE_NETWORK.html.gz.h"
#include "webh/html/PAGE_LOGIN.html.gz.h"
-
+*/
+/*
#include "webh/js/i18next.min.js.gz.h"
#include "webh/js/i18nextHttpBackend.min.js.gz.h"
#include "webh/js/functions.js.gz.h"
#include "webh/js/bootstrap.bundle.min.js.gz.h"
#include "webh/js/jquery-min.js.gz.h"
#include "webh/js/masonry.js.gz.h"
+*/
-#include "webh/css/style.css.gz.h"
-#include "webh/img/icons.svg.gz.h"
-#include "webh/img/logo.svg.gz.h"
+// #include "webh/css/style.css.gz.h"
+// #include "webh/img/icons.svg.gz.h"
+// #include "webh/img/logo.svg.gz.h"
+/*
#include "webh/json/en.json.gz.h"
#include "webh/json/uk.json.gz.h"
#include "webh/json/zh.json.gz.h"
@@ -56,6 +61,7 @@
#include "webh/json/it.json.gz.h"
#include "webh/json/pl.json.gz.h"
#include "webh/json/cz.json.gz.h"
+*/
// #define HTTP_DOWNLOAD_UNIT_SIZE 3000
@@ -71,7 +77,6 @@ extern CCTools CCTool;
extern struct SysVarsStruct vars;
extern struct ThisConfigStruct hwConfig;
extern BrdConfigStruct brdConfigs[BOARD_CFG_CNT];
-
extern struct SystemConfigStruct systemCfg;
extern struct NetworkConfigStruct networkCfg;
extern struct VpnConfigStruct vpnCfg;
@@ -84,33 +89,98 @@ extern IPAddress apIP;
bool wifiWebSetupInProgress = false;
bool eventOK = false;
-// extern const char *coordMode;
-
-// extern const char *deviceModel;
+// API strings
+const char *argAction = "action";
+const char *argPage = "page";
+const char *argParam = "param";
+const char *argFilename = "filename";
+const char *argCmd = "cmd";
+const char *argUrl = "url";
+const char *argType = "type";
+const char *argConf = "conf";
+const char *argLed = "led";
+const char *argAct = "act";
+const char *apiWrongArgs = "wrong args";
+const char *apiOk = "ok";
+const char *errLink = "Error getting link";
+
+// MIME types
const char *contTypeTextHtml = "text/html";
const char *contTypeTextJs = "text/javascript";
const char *contTypeTextCss = "text/css";
const char *contTypeTextSvg = "image/svg+xml";
+const char *contTypeJson = "application/json";
+
+// Misc. strings
const char *checked = "true";
const char *respHeaderName = "respValuesArr";
const char *respTimeZonesName = "respTimeZones";
-const char *contTypeJson = "application/json";
-const char *contTypeText = "text/plain";
-
const char *tempFile = "/fw.hex";
bool opened = false;
File fwFile;
-extern bool loadFileConfigMqtt();
-extern bool loadFileConfigWg();
+// extern bool loadFileConfigMqtt();
+// extern bool loadFileConfigWg();
WebServer serverWeb(80);
-// HTTPClient clientWeb;
WiFiClient eventsClient;
+// apiHandler() handler functions,
+// listed in index order
+static void apiDefault();
+static void apiGetPage();
+static void apiGetParam();
+static void apiStartWifiScan();
+static void apiWifiScanStatus();
+static void apiGetLog();
+static void apiCmd();
+static void apiWifiConnnectStat();
+static void apiGetFile();
+static void apiDelFile();
+static void apiGetFileList();
+
+// apiCMD() handler functions,
+// listed in index order
+static void apiCmdDefault(String &result);
+static void apiCmdZbRouterRecon(String &result);
+static void apiCmdZbRestart(String &result);
+static void apiCmdZbEnableBsl(String &result);
+static void apiCmdEspReset(String &result);
+static void apiCmdAdapterLan(String &result);
+static void apiCmdAdapterUsb(String &result);
+static void apiCmdLedAct(String &result);
+static void apiCmdZbFlash(String &result);
+static void apiCmdClearLog(String &result);
+static void apiCmdUpdateUrl(String &result);
+static void apiCmdZbCheckFirmware(String &result);
+static void apiCmdZbLedToggle(String &result);
+static void apiCmdFactoryReset(String &result);
+static void apiCmdDnsCheck(String &result);
+static void apiCmdBoardName(String &result);
+
+// functions called exactly once each
+// from getRootData():
+static inline void getRootEthTab(DynamicJsonDocument &doc,
+ bool update,
+ const String &noConn);
+static inline void getRootWifi(DynamicJsonDocument &doc,
+ bool update,
+ const String &noConn);
+static inline void getRootHwMisc(DynamicJsonDocument &doc,
+ bool update);
+static inline void getRootVpnWireGuard(DynamicJsonDocument &doc);
+static inline void getRootVpnHusarnet(DynamicJsonDocument &doc);
+static inline void getRootUptime(DynamicJsonDocument &doc);
+static inline void getRootCpuTemp(DynamicJsonDocument &doc);
+static inline void getRootOneWireTemp(DynamicJsonDocument &doc);
+static inline void getRootHeapsize(DynamicJsonDocument &doc);
+static inline void getRootNvsStats(DynamicJsonDocument &doc);
+static inline void getRootSockets(DynamicJsonDocument &doc);
+static inline void getRootTime(DynamicJsonDocument &doc);
+
void webServerHandleClient()
{
serverWeb.handleClient();
@@ -126,7 +196,7 @@ void redirectLogin(int msg = 0)
serverWeb.sendHeader("Location", path);
serverWeb.sendHeader("Cache-Control", "no-cache");
- serverWeb.send(301);
+ serverWeb.send(HTTP_CODE_MOVED_PERMANENTLY);
}
void handleLoader()
@@ -140,12 +210,14 @@ void handleLoader()
redirectLogin();
return;
}
- sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len);
+ // sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len);
+ sendGzipFromFS("/html/loader.html.gz", contTypeTextHtml);
}
void initWebServer()
{
/* ----- LANG FILES | START -----*/
+ /*
serverWeb.on("/lg/en.json", []()
{ sendGzip(contTypeJson, en_json_gz, en_json_gz_len); });
serverWeb.on("/lg/uk.json", []()
@@ -172,28 +244,78 @@ void initWebServer()
{ sendGzip(contTypeJson, pl_json_gz, pl_json_gz_len); });
serverWeb.on("/lg/cz.json", []()
{ sendGzip(contTypeJson, cz_json_gz, cz_json_gz_len); });
+ */
+ serverWeb.on("/lg/en.json", []()
+ { sendGzipFromFS("/json/en.json.gz", contTypeJson); });
+ serverWeb.on("/lg/uk.json", []()
+ { sendGzipFromFS("/json/uk.json.gz", contTypeJson); });
+ serverWeb.on("/lg/zh.json", []()
+ { sendGzipFromFS("/json/zh.json.gz", contTypeJson); });
+ serverWeb.on("/lg/es.json", []()
+ { sendGzipFromFS("/json/es.json.gz", contTypeJson); });
+ serverWeb.on("/lg/pt.json", []()
+ { sendGzipFromFS("/json/pt.json.gz", contTypeJson); });
+ serverWeb.on("/lg/ru.json", []()
+ { sendGzipFromFS("/json/ru.json.gz", contTypeJson); });
+ serverWeb.on("/lg/fr.json", []()
+ { sendGzipFromFS("/json/fr.json.gz", contTypeJson); });
+ serverWeb.on("/lg/de.json", []()
+ { sendGzipFromFS("/json/de.json.gz", contTypeJson); });
+ serverWeb.on("/lg/ja.json", []()
+ { sendGzipFromFS("/json/ja.json.gz", contTypeJson); });
+ serverWeb.on("/lg/tr.json", []()
+ { sendGzipFromFS("/json/tr.json.gz", contTypeJson); });
+ serverWeb.on("/lg/it.json", []()
+ { sendGzipFromFS("/json/it.json.gz", contTypeJson); });
+ serverWeb.on("/lg/pl.json", []()
+ { sendGzipFromFS("/json/pl.json.gz", contTypeJson); });
+ serverWeb.on("/lg/cz.json", []()
+ { sendGzipFromFS("/json/cz.json.gz", contTypeJson); });
+
/* ----- LANG FILES | END -----*/
/* ----- JS and CSS FILES | START -----*/
+ /*
serverWeb.on("/js/i18next.min.js", []()
{ sendGzip(contTypeTextJs, i18next_min_js_gz, i18next_min_js_gz_len); });
+serverWeb.on("/js/i18nextHttpBackend.min.js", []()
+ { sendGzip(contTypeTextJs, i18nextHttpBackend_min_js_gz, i18nextHttpBackend_min_js_gz_len); });
+serverWeb.on("/js/bootstrap.bundle.min.js", []()
+ { sendGzip(contTypeTextJs, bootstrap_bundle_min_js_gz, bootstrap_bundle_min_js_gz_len); });
+serverWeb.on("/js/masonry.js", []()
+ { sendGzip(contTypeTextJs, masonry_js_gz, masonry_js_gz_len); });
+serverWeb.on("/js/functions.js", []()
+ { sendGzip(contTypeTextJs, functions_js_gz, functions_js_gz_len); });
+serverWeb.on("/js/jquery-min.js", []()
+ { sendGzip(contTypeTextJs, jquery_min_js_gz, jquery_min_js_gz_len); });
+ */
+ serverWeb.on("/js/i18next.min.js", []()
+ { sendGzipFromFS("/js/i18next.min.js.gz", contTypeTextJs); });
serverWeb.on("/js/i18nextHttpBackend.min.js", []()
- { sendGzip(contTypeTextJs, i18nextHttpBackend_min_js_gz, i18nextHttpBackend_min_js_gz_len); });
+ { sendGzipFromFS("/js/i18nextHttpBackend.min.js.gz", contTypeTextJs); });
serverWeb.on("/js/bootstrap.bundle.min.js", []()
- { sendGzip(contTypeTextJs, bootstrap_bundle_min_js_gz, bootstrap_bundle_min_js_gz_len); });
+ { sendGzipFromFS("/js/bootstrap.bundle.min.js.gz", contTypeTextJs); });
serverWeb.on("/js/masonry.js", []()
- { sendGzip(contTypeTextJs, masonry_js_gz, masonry_js_gz_len); });
+ { sendGzipFromFS("/js/masonry.js.gz", contTypeTextJs); });
serverWeb.on("/js/functions.js", []()
- { sendGzip(contTypeTextJs, functions_js_gz, functions_js_gz_len); });
+ { sendGzipFromFS("/js/functions.js.gz", contTypeTextJs); });
serverWeb.on("/js/jquery-min.js", []()
- { sendGzip(contTypeTextJs, jquery_min_js_gz, jquery_min_js_gz_len); });
+ { sendGzipFromFS("/js/jquery-min.js.gz", contTypeTextJs); });
+
+ /*serverWeb.on("/css/style.css", []()
+ { sendGzip(contTypeTextCss, required_css_gz, required_css_gz_len); });*/
serverWeb.on("/css/style.css", []()
- { sendGzip(contTypeTextCss, required_css_gz, required_css_gz_len); });
+ { sendGzipFromFS("/css/style.css.gz", contTypeTextCss); });
/* ----- JS and CSS FILES | END -----*/
/* ----- SVG FILES | START -----*/
+ /* serverWeb.on("/logo.svg", []()
+ { sendGzip(contTypeTextSvg, logo_svg_gz, logo_svg_gz_len); }); */
serverWeb.on("/logo.svg", []()
- { sendGzip(contTypeTextSvg, logo_svg_gz, logo_svg_gz_len); });
+ { sendGzipFromFS("/img/logo.svg.gz", contTypeTextSvg); });
+
serverWeb.on("/icons.svg", []()
- { sendGzip(contTypeTextSvg, icons_svg_gz, icons_svg_gz_len); });
+ { sendGzipFromFS("/img/icons.svg.gz", contTypeTextSvg); });
+ /* serverWeb.on("/icons.svg", []()
+ { sendGzip(contTypeTextSvg, icons_svg_gz, icons_svg_gz_len); }); */
serverWeb.onNotFound(handleNotFound);
@@ -237,7 +359,7 @@ void initWebServer()
/* ----- OTA | END -----*/
const char *headerkeys[] = {"Content-Length", "Cookie"};
- size_t headerkeyssize = sizeof(headerkeys) / sizeof(char *);
+ constexpr size_t headerkeyssize = sizeof(headerkeys) / sizeof(char *);
serverWeb.collectHeaders(headerkeys, headerkeyssize);
serverWeb.begin();
LOGD("done");
@@ -254,7 +376,7 @@ bool captivePortal()
{
LOGD("Request redirected to captive portal");
serverWeb.sendHeader("Location", String("http://") + apIP.toString(), true);
- serverWeb.send(302, "text/plain", "");
+ serverWeb.send(HTTP_CODE_FOUND, contTypeText, "");
serverWeb.client().stop();
return true;
}
@@ -298,13 +420,16 @@ void handleNotFound()
serverWeb.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
serverWeb.sendHeader("Pragma", "no-cache");
serverWeb.sendHeader("Expires", "-1");
- serverWeb.send(404, "text/plain", message);
+ serverWeb.send(HTTP_CODE_NOT_FOUND, contTypeText, message);
}
void handleUpdateRequest()
{
- serverWeb.sendHeader("Connection", "close");
- serverWeb.send(HTTP_CODE_OK, contTypeText, "Upload OK. Try to flash...");
+ serverWeb.sendHeader("Connection",
+ "close");
+ serverWeb.send(HTTP_CODE_OK,
+ contTypeText,
+ "Upload OK. Try to flash...");
}
void handleEspUpdateUpload()
@@ -316,16 +441,35 @@ void handleEspUpdateUpload()
HTTPUpload &upload = serverWeb.upload();
static long contentLength = 0;
+ static bool isSpiffsUpdate = false;
+
if (upload.status == UPLOAD_FILE_START)
{
- LOGD("hostHeader: %s", serverWeb.hostHeader());
contentLength = serverWeb.header("Content-Length").toInt();
- LOGD("contentLength: %s", String(contentLength));
- LOGD("Update ESP from file %s size: %s", String(upload.filename.c_str()), String(upload.totalSize));
- LOGD("upload.currentSize %s", String(upload.currentSize));
- if (!Update.begin(contentLength))
+ String filename = upload.filename.c_str();
+ LOGD("hostHeader: %s", serverWeb.hostHeader().c_str());
+ LOGD("contentLength: %s", String(contentLength).c_str());
+ LOGD("Update ESP from file %s size: %s", filename.c_str(), String(upload.totalSize).c_str());
+ LOGD("upload.currentSize %s", String(upload.currentSize).c_str());
+
+ // Определяем, является ли это обновлением файловой системы
+ if (filename.endsWith(".fs.bin"))
{
- Update.printError(Serial);
+ isSpiffsUpdate = true;
+ if (!Update.begin(contentLength, U_SPIFFS)) // contentLength
+ {
+ Update.printError(Serial);
+ return;
+ }
+ }
+ else
+ {
+ isSpiffsUpdate = false;
+ if (!Update.begin(contentLength, U_FLASH)) // contentLength
+ {
+ Update.printError(Serial);
+ return;
+ }
}
Update.onProgress(progressFunc);
}
@@ -340,24 +484,43 @@ void handleEspUpdateUpload()
{
if (Update.end(true))
{
- LOGD("Update success. Rebooting...");
- ESP.restart();
+ serverWeb.send(HTTP_CODE_OK, contTypeText, "");
+ if (isSpiffsUpdate)
+ {
+ LOGD("SPIFFS Update success. Rebooting...");
+ }
+ else
+ {
+ LOGD("Firmware Update success. Rebooting...");
+ }
+ restartDevice();
}
else
{
+ serverWeb.send(HTTP_CODE_NOT_FOUND, contTypeText, "Error");
LOGD("Update error: ");
Update.printError(Serial);
}
}
+ else if (upload.status == UPLOAD_FILE_ABORTED)
+ {
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, "Aborted");
+ Update.end();
+ LOGD("Update aborted");
+ }
}
void handleEvents()
{
if (is_authenticated())
{
+ if (eventsClient)
+ {
+ eventsClient.stop();
+ }
eventsClient = serverWeb.client();
if (eventsClient)
- { // send events header
+ {
eventsClient.println("HTTP/1.1 200 OK");
eventsClient.println("Content-Type: text/event-stream;");
eventsClient.println("Connection: close");
@@ -369,25 +532,62 @@ void handleEvents()
}
}
-void sendEvent(const char *event, const uint8_t evsz, const String data)
+void sendEvent(const char *event,
+ const uint8_t evsz,
+ const String data)
{
if (eventsClient)
{
char evnmArr[10 + evsz];
- sprintf(evnmArr, "event: %s\n", event);
+ snprintf(evnmArr, sizeof(evnmArr), "event: %s\n", event);
eventsClient.print(evnmArr);
eventsClient.print(String("data: ") + data + "\n\n");
- // eventsClient.println();
eventsClient.flush();
}
}
-void sendGzip(const char *contentType, const uint8_t content[], uint16_t contentLen)
+void sendGzipFromFS(const char *path, const char *contentType)
+{
+ File file = LittleFS.open(path, FILE_READ);
+ if (!file)
+ {
+ serverWeb.send(HTTP_CODE_NOT_FOUND, contTypeText, "File not found");
+ LOGD("File not found: %s", path);
+ return;
+ }
+
+ size_t fileSize = file.size();
+ if (fileSize == 0)
+ {
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, "File is empty");
+ LOGD("File is empty: %s", path);
+ file.close();
+ return;
+ }
+
+ LOGD("File - %s, Size - %d", path, fileSize);
+
+ serverWeb.streamFile(file, contentType);
+ file.close();
+}
+
+/*
+void sendGzip(const char *contentType,
+ const uint8_t content[],
+ uint16_t contentLen)
{
- serverWeb.sendHeader(F("Content-Encoding"), F("gzip"));
- serverWeb.send_P(HTTP_CODE_OK, contentType, (const char *)content, contentLen);
+ serverWeb.sendHeader(F("Content-Encoding"),
+ F("gzip"));
+ serverWeb.send_P(HTTP_CODE_OK,
+ contentType,
+ (const char *)content,
+ contentLen);
}
+*/
+// This isn't called from anywhere,
+// does it even work?
+/*
void hex2bin(uint8_t *out, const char *in)
{
// uint8_t sz = 0;
@@ -410,482 +610,605 @@ void hex2bin(uint8_t *out, const char *in)
// sz++;
}
}
+*/
-void handleApi()
-{ // http://xzg.local/api?action=0&page=0
- enum API_ACTION_t : uint8_t
- {
- API_GET_PAGE,
- API_GET_PARAM,
- API_STARTWIFISCAN,
- API_WIFISCANSTATUS,
- API_GET_FILELIST,
- API_GET_FILE,
- API_SEND_HEX,
- API_WIFICONNECTSTAT,
- API_CMD,
- API_GET_LOG,
- API_DEL_FILE //,
- // API_FLASH_ZB
- };
- const char *action = "action";
- const char *page = "page";
- // const char *Authentication = "Authentication";
- const char *param = "param";
- const char *wrongArgs = "wrong args";
- const char *ok = "ok";
- const char *argFilename = "filename";
-
- if (!is_authenticated())
- {
- redirectLogin(1);
- return;
- }
+static void apiGetLog()
+{
+ String result;
+ result = logPrint();
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+}
- if (serverWeb.argName(0) != action)
+static void apiCmdUpdateUrl(String &result)
+{
+ if (serverWeb.hasArg(argUrl))
{
- serverWeb.send(500, contTypeText, wrongArgs);
+ getEspUpdate(serverWeb.arg(argUrl));
}
else
{
- const uint8_t action = serverWeb.arg(action).toInt();
- switch (action)
- {
- case API_GET_LOG:
- {
- String result;
- result = logPrint();
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- }
- break;
- case API_CMD:
- {
- enum CMD_t : uint8_t
- { // cmd list for buttons starts from 0
- CMD_ZB_ROUTER_RECON,
- CMD_ZB_RST,
- CMD_ZB_BSL,
- CMD_ESP_RES,
- CMD_ADAP_LAN,
- CMD_ADAP_USB,
- CMD_LED_ACT,
- CMD_ZB_FLASH,
- CMD_CLEAR_LOG,
- CMD_ESP_UPD_URL,
- CMD_ZB_CHK_FW,
- CMD_ZB_CHK_HW,
- CMD_ZB_LED_TOG,
- CMD_ESP_FAC_RES,
- CMD_ZB_ERASE_NVRAM
- };
- String result = wrongArgs;
- const char *argCmd = "cmd";
- const char *argUrl = "url";
- const char *argConf = "conf";
- const char *argLed = "led";
- const char *argAct = "act";
-
- if (serverWeb.hasArg(argCmd))
- {
- result = "ok";
- switch (serverWeb.arg(argCmd).toInt())
- {
- case CMD_CLEAR_LOG:
- logClear();
- break;
- case CMD_ZB_ROUTER_RECON:
- zigbeeRouterRejoin();
- break;
- case CMD_ZB_RST:
- zigbeeRestart();
- break;
- case CMD_ZB_BSL:
- zigbeeEnableBSL();
- break;
- case CMD_ZB_ERASE_NVRAM:
- xTaskCreate(zbEraseNV, "zbEraseNV", 2048, NULL, 5, NULL);
- break;
- case CMD_ESP_RES:
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- delay(250);
- ESP.restart();
- break;
- case CMD_ADAP_LAN:
- usbModeSet(XZG);
- break;
- case CMD_ADAP_USB:
- usbModeSet(ZIGBEE);
- break;
- case CMD_ESP_UPD_URL:
- if (serverWeb.hasArg(argUrl))
- getEspUpdate(serverWeb.arg(argUrl));
- else
- {
- String link = fetchGitHubReleaseInfo();
- LOGD("%s", link.c_str());
- if (link)
- {
- getEspUpdate(link);
- }
- else
- {
- LOGW("Error getting link");
- }
- }
- break;
- case CMD_ZB_CHK_FW:
- if (zbFwCheck())
- {
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- }
- else
- {
- serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, result);
- }
- break;
- case CMD_ZB_CHK_HW:
- zbHwCheck();
- break;
- case CMD_ZB_LED_TOG:
- if (zbLedToggle())
- {
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- }
- else
- {
- serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, result);
- }
- break;
- case CMD_ESP_FAC_RES:
- if (serverWeb.hasArg(argConf))
- if (serverWeb.arg(argConf).toInt() == 1)
- {
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- factoryReset();
- }
- else
- {
- serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
- }
- break;
- case CMD_LED_ACT:
- if (serverWeb.hasArg(argLed) && serverWeb.hasArg(argAct))
- {
- int ledNum = serverWeb.arg(argLed).toInt();
- int actNum = serverWeb.arg(argAct).toInt();
-
- LED_t ledEnum = static_cast(ledNum);
- LEDMode actEnum = static_cast(actNum);
-
- if (static_cast(ledEnum) == ledNum && static_cast(actEnum) == actNum)
- {
- String tag = "API";
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- if (ledNum == MODE_LED)
- {
- LOGD("%s led %d", ledControl.modeLED.name, actNum);
- ledControl.modeLED.mode = static_cast(actNum);
- }
- else if (ledNum == POWER_LED)
- {
- LOGD("%s led %d", ledControl.powerLED.name, actNum);
- ledControl.powerLED.mode = static_cast(actNum);
- }
- }
- else
- {
- serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
- }
- }
- else
- {
- serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
- }
- break;
- case CMD_ZB_FLASH:
- if (serverWeb.hasArg(argUrl))
- {
- flashZbUrl(serverWeb.arg(argUrl));
- }
- else
- {
- flashZbUrl("https://github.com/xyzroe/XZG/raw/zb_fws/ti/coordinator/CC1352P2_CC2652P_launchpad_coordinator_20240315.bin");
- }
- break;
- default:
- serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
- break;
- }
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- }
- }
- break;
- case API_WIFICONNECTSTAT:
+ if (serverWeb.hasArg(argType))
{
- String result;
- StaticJsonDocument<70> doc;
- const char *connected = "connected";
- if (WiFi.status() == WL_CONNECTED)
+ // String link = fetchLatestEspFw();
+ FirmwareInfo fwInfo = fetchLatestEspFw(serverWeb.arg(argType));
+ if (fwInfo.url)
{
- doc[connected] = true;
- doc["ip"] = WiFi.localIP().toString();
+ getEspUpdate(fwInfo.url);
}
else
{
- doc[connected] = false;
+ LOGW("%s", String(errLink).c_str());
}
- serializeJson(doc, result);
- serverWeb.send(HTTP_CODE_OK, contTypeJson, result);
}
- break;
- case API_GET_FILE:
- {
- String result = wrongArgs;
+ }
+}
- if (serverWeb.hasArg(argFilename))
- {
- String filename = "/" + serverWeb.arg(argFilename);
- File file = LittleFS.open(filename, "r");
- if (!file)
- return;
- result = "";
- while (file.available() && result.length() < 500)
- {
- result += (char)file.read();
- }
- file.close();
- }
- serverWeb.send(HTTP_CODE_OK, contTypeText, result);
- }
- break;
- case API_DEL_FILE:
- {
- String result = wrongArgs;
+static void apiCmdZbCheckFirmware(String &result)
+{
+ if (zbFwCheck())
+ {
+ printLogMsg("[RCP] " + CCTool.chip.fwRev);
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ }
+ else
+ {
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, result);
+ }
+}
- if (serverWeb.hasArg(argFilename))
- {
- String filename = "/" + serverWeb.arg(argFilename);
- LOGW("Remove file %s", filename.c_str());
- LittleFS.remove(filename);
- }
+static void apiCmdZbLedToggle(String &result)
+{
+ if (zbLedToggle())
+ {
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ }
+ else
+ {
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, result);
+ }
+}
+
+static void apiCmdFactoryReset(String &result)
+{
+ if (serverWeb.hasArg(argConf))
+ {
+ if (serverWeb.arg(argConf).toInt() == 1)
+ {
serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ factoryReset();
}
- break;
- case API_GET_PARAM:
+ else
{
- String resp = wrongArgs;
- if (serverWeb.hasArg(param))
- {
- if (serverWeb.arg(param) == "refreshLogs")
- {
- resp = (String)systemCfg.refreshLogs;
- }
- else if (serverWeb.arg(param) == "update_root")
- {
- resp = getRootData(true);
- }
- else if (serverWeb.arg(param) == "coordMode")
- {
- if (wifiWebSetupInProgress)
- {
- resp = "1";
- }
- else
- {
- resp = (String)systemCfg.workMode;
- }
- }
- else if (serverWeb.arg(param) == "zbFwVer")
- {
- resp = String(CCTool.chip.fwRev);
- }
- else if (serverWeb.arg(param) == "zbHwVer")
- {
- resp = String(CCTool.chip.hwRev);
- }
- else if (serverWeb.arg(param) == "espVer")
- {
- resp = VERSION;
- }
- else if (serverWeb.arg(param) == "wifiEnable")
- {
- resp = networkCfg.wifiEnable;
- }
- else if (serverWeb.arg(param) == "all")
- {
- resp = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg);
- }
- else if (serverWeb.arg(param) == "vars")
- {
- resp = makeJsonConfig(NULL, NULL, NULL, NULL, &vars);
- }
- else if (serverWeb.arg(param) == "root")
- {
- resp = getRootData();
- }
- }
- serverWeb.send(HTTP_CODE_OK, contTypeText, resp);
+ serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
}
- break;
- case API_STARTWIFISCAN:
- if (WiFi.getMode() == WIFI_OFF)
- { // enable wifi for scan
- WiFi.mode(WIFI_STA);
- }
- // } else if (WiFi.getMode() == WIFI_AP) { // enable sta for scan
- // WiFi.mode(WIFI_AP_STA);
- // }
- WiFi.scanNetworks(true);
- serverWeb.send(HTTP_CODE_OK, contTypeTextHtml, ok);
- break;
- case API_WIFISCANSTATUS:
+ }
+}
+
+static void apiCmdLedAct(String &result)
+{
+ if (serverWeb.hasArg(argLed) && serverWeb.hasArg(argAct))
+ {
+ int ledNum = serverWeb.arg(argLed).toInt();
+ int actNum = serverWeb.arg(argAct).toInt();
+
+ LED_t ledEnum = static_cast(ledNum);
+ LEDMode actEnum = static_cast(actNum);
+
+ if (static_cast(ledEnum) == ledNum && static_cast(actEnum) == actNum)
{
- static uint8_t timeout = 0;
- DynamicJsonDocument doc(1024);
- String result = "";
- int16_t scanRes = WiFi.scanComplete();
- const char *scanDone = "scanDone";
- doc[scanDone] = false;
- if (scanRes == -2)
- {
- WiFi.scanNetworks(true);
- }
- else if (scanRes > 0)
- {
- doc[scanDone] = true;
- JsonArray wifi = doc.createNestedArray("wifi");
- for (int i = 0; i < scanRes; ++i)
- {
- JsonObject wifi_0 = wifi.createNestedObject();
- wifi_0["ssid"] = WiFi.SSID(i);
- wifi_0["rssi"] = WiFi.RSSI(i);
- wifi_0["channel"] = WiFi.channel(i);
- wifi_0["secure"] = WiFi.encryptionType(i);
- }
- WiFi.scanDelete();
- }
- if (timeout < 10)
+ String tag = "API";
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ if (ledNum == MODE_LED)
{
- timeout++;
+ LOGD("%s led %d", ledControl.modeLED.name.c_str(), actNum);
+ ledControl.modeLED.mode = static_cast(actNum);
}
- else
+ else if (ledNum == POWER_LED)
{
- doc[scanDone] = true;
- WiFi.scanDelete();
- timeout = 0;
+ LOGD("%s led %d", ledControl.powerLED.name.c_str(), actNum);
+ ledControl.powerLED.mode = static_cast(actNum);
}
- serializeJson(doc, result);
- serverWeb.send(HTTP_CODE_OK, contTypeJson, result);
- break;
}
- case API_GET_PAGE:
- if (!serverWeb.arg(page).length() > 0)
- {
- LOGW("wrong arg 'page' %s", serverWeb.argName(1));
- serverWeb.send(500, contTypeText, wrongArgs);
- return;
- }
- switch (serverWeb.arg(page).toInt())
- {
- case API_PAGE_ROOT:
- handleRoot();
- sendGzip(contTypeTextHtml, PAGE_ROOT_html_gz, PAGE_ROOT_html_gz_len);
- break;
- case API_PAGE_GENERAL:
- handleGeneral();
- sendGzip(contTypeTextHtml, PAGE_GENERAL_html_gz, PAGE_GENERAL_html_gz_len);
- break;
- case API_PAGE_NETWORK:
- handleNetwork();
- sendGzip(contTypeTextHtml, PAGE_NETWORK_html_gz, PAGE_NETWORK_html_gz_len);
- break;
- case API_PAGE_ZIGBEE:
- handleSerial();
- sendGzip(contTypeTextHtml, PAGE_ZIGBEE_html_gz, PAGE_ZIGBEE_html_gz_len);
- break;
- case API_PAGE_SECURITY:
- handleSecurity();
- sendGzip(contTypeTextHtml, PAGE_SECURITY_html_gz, PAGE_SECURITY_html_gz_len);
- break;
- case API_PAGE_TOOLS:
- handleTools();
- sendGzip(contTypeTextHtml, PAGE_TOOLS_html_gz, PAGE_TOOLS_html_gz_len);
- break;
- case API_PAGE_ABOUT:
- // handleAbout();
- sendGzip(contTypeTextHtml, PAGE_ABOUT_html_gz, PAGE_ABOUT_html_gz_len);
- break;
- case API_PAGE_MQTT:
- handleMqtt();
- sendGzip(contTypeTextHtml, PAGE_MQTT_html_gz, PAGE_MQTT_html_gz_len);
- break;
- case API_PAGE_VPN:
- handleVpn();
- sendGzip(contTypeTextHtml, PAGE_VPN_html_gz, PAGE_VPN_html_gz_len);
- break;
- default:
- break;
- }
- break;
- case API_GET_FILELIST:
+ else
{
- String fileList = "";
- DynamicJsonDocument doc(512);
- JsonArray files = doc.createNestedArray("files");
- File root = LittleFS.open("/");
- File file = root.openNextFile();
- while (file)
- {
- JsonObject jsonfile = files.createNestedObject();
- jsonfile["filename"] = String(file.name());
- jsonfile["size"] = file.size();
- file = root.openNextFile();
- }
- root = LittleFS.open("/config/");
- file = root.openNextFile();
- while (file)
- {
- JsonObject jsonfile = files.createNestedObject();
- jsonfile["filename"] = String("/config/" + String(file.name()));
- jsonfile["size"] = file.size();
- file = root.openNextFile();
- }
- serializeJson(doc, fileList);
- serverWeb.send(HTTP_CODE_OK, contTypeJson, fileList);
- break;
- }
-
- default:
- LOGW("switch (action) err");
- break;
+ serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
}
}
+ else
+ {
+ serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
+ }
}
-void handleSaveParams()
+static void apiCmdZbFlash(String &result)
{
- if (!is_authenticated())
- return;
- updateConfiguration(serverWeb, systemCfg, networkCfg, vpnCfg, mqttCfg);
+ if (serverWeb.hasArg(argUrl))
+ {
+ flashZbUrl(serverWeb.arg(argUrl));
+ }
+ else
+ {
+ String link = fetchLatestZbFw();
+ if (link)
+ {
+ flashZbUrl(link);
+ }
+ else
+ {
+ LOGW("%s", String(errLink).c_str());
+ }
+ }
}
-void printEachKeyValuePair(const String &jsonString)
+static void apiCmdBoardName(String &result)
{
- DynamicJsonDocument doc(1024);
- DeserializationError error = deserializeJson(doc, jsonString);
-
- if (error)
+ if (serverWeb.hasArg("board"))
{
+ String brdName = serverWeb.arg("board");
+ brdName.toCharArray(hwConfig.board, sizeof(hwConfig.board));
- return;
- }
+ /*File configFile = LittleFS.open(configFileHw, FILE_READ);
+ if (!configFile)
+ {
+ Serial.println("Failed to open config file for reading");
+ return;
+ }
- const uint8_t eventLen = 100;
+ DynamicJsonDocument config(1024);
+ DeserializationError error = deserializeJson(config, configFile);
+ if (error)
+ {
+ Serial.println("Failed to parse config file");
+ configFile.close();
+ return;
+ }
- for (JsonPair kv : doc.as())
- {
- DynamicJsonDocument pairDoc(256);
- pairDoc[kv.key().c_str()] = kv.value();
+ configFile.close();
+ config["board"] = hwConfig.board;
+
+ writeDefaultConfig(configFileHw, config);*/
+
+ brdName.toCharArray(hwConfig.board, sizeof(hwConfig.board));
+
+ hwConfig.board[sizeof(hwConfig.board) - 1] = '\0';
+
+ saveHwConfig(hwConfig);
+
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ }
+ else
+ {
+ serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
+ }
+}
+
+static void apiCmdDefault(String &result)
+{
+ serverWeb.send(HTTP_CODE_BAD_REQUEST, contTypeText, result);
+}
+
+static void apiCmdZbRouterRecon(String &result)
+{
+ zigbeeRouterRejoin();
+}
+
+static void apiCmdZbRestart(String &result)
+{
+ zigbeeRestart();
+}
+
+static void apiCmdZbEnableBsl(String &result)
+{
+ zigbeeEnableBSL();
+}
+
+static void apiCmdEspReset(String &result)
+{
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ delay(250);
+ restartDevice();
+}
+
+static void apiCmdAdapterLan(String &result)
+{
+ usbModeSet(XZG);
+}
+
+static void apiCmdAdapterUsb(String &result)
+{
+ usbModeSet(ZIGBEE);
+}
+
+static void apiCmdClearLog(String &result)
+{
+ logClear();
+}
+
+static void apiCmdZbCheckHardware(String &result)
+{
+ zbHwCheck();
+}
+
+static void apiCmdEraseNvram(String &result)
+{
+ xTaskCreate(zbEraseNV, "zbEraseNV", 2048, NULL, 5, NULL);
+}
+
+static void apiCmdDnsCheck(String &result)
+{
+ // checkDNS();
+}
+
+static void apiCmd()
+{
+ static void (*apiCmdFunctions[])(String &result) =
+ {
+ apiCmdDefault,
+ apiCmdZbRouterRecon,
+ apiCmdZbRestart,
+ apiCmdZbEnableBsl,
+ apiCmdEspReset,
+ apiCmdAdapterLan,
+ apiCmdAdapterUsb,
+ apiCmdLedAct,
+ apiCmdZbFlash,
+ apiCmdClearLog,
+ apiCmdUpdateUrl,
+ apiCmdZbCheckFirmware,
+ apiCmdZbCheckHardware,
+ apiCmdZbLedToggle,
+ apiCmdFactoryReset,
+ apiCmdEraseNvram,
+ apiCmdDnsCheck,
+ apiCmdBoardName};
+ constexpr int numFunctions = sizeof(apiCmdFunctions) / sizeof(apiCmdFunctions[0]);
+ String result = apiWrongArgs;
+
+ if (serverWeb.hasArg(argCmd))
+ {
+ result = "ok";
+
+ // I add 1 to allow 0 to be default+overflow/invalid case.
+ // Ideally, the client would send 1-indexed "cmd"s
+ // but then I'd need to modify this in ALL of the client code...
+ uint8_t command = serverWeb.arg(argCmd).toInt() + 1;
+ bool boundsCheck = command < numFunctions;
+
+ apiCmdFunctions[command * boundsCheck](result);
+
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+ }
+}
+
+static void apiWifiConnnectStat()
+{
+ String result;
+ StaticJsonDocument<70> doc;
+ const char *connected = "connected";
+ if (WiFi.status() == WL_CONNECTED)
+ {
+ doc[connected] = true;
+ doc["ip"] = WiFi.localIP().toString();
+ }
+ else
+ {
+ doc[connected] = false;
+ }
+ serializeJson(doc, result);
+ serverWeb.send(HTTP_CODE_OK, contTypeJson, result);
+}
+
+static void apiGetFile()
+{
+ String result = apiWrongArgs;
+
+ if (serverWeb.hasArg(argFilename))
+ {
+ String filename = "/" + serverWeb.arg(argFilename);
+ File file = LittleFS.open(filename, "r");
+ if (!file)
+ {
+ return;
+ }
+ result = "";
+ while (file.available() && result.length() < 500)
+ {
+ result += (char)file.read();
+ }
+ file.close();
+ }
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+}
+
+static void apiDelFile()
+{
+ String result = apiWrongArgs;
+
+ if (serverWeb.hasArg(argFilename))
+ {
+ String filename = "/" + serverWeb.arg(argFilename);
+ LOGW("Remove file %s", filename.c_str());
+ LittleFS.remove(filename);
+ }
+ serverWeb.send(HTTP_CODE_OK, contTypeText, result);
+}
+
+static void apiGetParam()
+{
+ String resp = apiWrongArgs;
+ if (serverWeb.hasArg(argParam))
+ {
+ if (serverWeb.arg(argParam) == "refreshLogs")
+ {
+ resp = (String)systemCfg.refreshLogs;
+ }
+ else if (serverWeb.arg(argParam) == "update_root")
+ {
+ resp = getRootData(true);
+ }
+ else if (serverWeb.arg(argParam) == "coordMode")
+ {
+ if (wifiWebSetupInProgress)
+ {
+ resp = "1";
+ }
+ else
+ {
+ resp = (String)systemCfg.workMode;
+ }
+ }
+ else if (serverWeb.arg(argParam) == "zbFwVer")
+ {
+ resp = String(CCTool.chip.fwRev);
+ }
+ else if (serverWeb.arg(argParam) == "zbHwVer")
+ {
+ resp = String(CCTool.chip.hwRev);
+ }
+ else if (serverWeb.arg(argParam) == "espVer")
+ {
+ resp = VERSION;
+ }
+ else if (serverWeb.arg(argParam) == "wifiEnable")
+ {
+ resp = networkCfg.wifiEnable;
+ }
+ else if (serverWeb.arg(argParam) == "all")
+ {
+ resp = makeJsonConfig(&networkCfg, &vpnCfg, &mqttCfg, &systemCfg);
+ }
+ else if (serverWeb.arg(argParam) == "vars")
+ {
+ resp = makeJsonConfig(NULL, NULL, NULL, NULL, &vars);
+ }
+ else if (serverWeb.arg(argParam) == "root")
+ {
+ resp = getRootData();
+ }
+ }
+ serverWeb.send(HTTP_CODE_OK, contTypeText, resp);
+}
+
+static void apiStartWifiScan()
+{
+ if (WiFi.getMode() == WIFI_OFF)
+ { // enable wifi for scan
+ WiFi.mode(WIFI_STA);
+ }
+ // } else if (WiFi.getMode() == WIFI_AP) { // enable sta for scan
+ // WiFi.mode(WIFI_AP_STA);
+ // }
+ WiFi.scanNetworks(true);
+ serverWeb.send(HTTP_CODE_OK, contTypeTextHtml, apiOk);
+}
+
+static void apiWifiScanStatus()
+{
+ static uint8_t timeout = 0;
+ DynamicJsonDocument doc(1024);
+ String result = "";
+ int16_t scanRes = WiFi.scanComplete();
+ const char *scanDone = "scanDone";
+
+ doc[scanDone] = false;
+ if (scanRes == -2)
+ {
+ WiFi.scanNetworks(true);
+ }
+ else if (scanRes > 0)
+ {
+ doc[scanDone] = true;
+ JsonArray wifi = doc.createNestedArray("wifi");
+ for (int i = 0; i < scanRes; ++i)
+ {
+ JsonObject wifi_0 = wifi.createNestedObject();
+ wifi_0["ssid"] = WiFi.SSID(i);
+ wifi_0["rssi"] = WiFi.RSSI(i);
+ wifi_0["channel"] = WiFi.channel(i);
+ wifi_0["secure"] = WiFi.encryptionType(i);
+ }
+ WiFi.scanDelete();
+ }
+ if (timeout < 10)
+ {
+ timeout++;
+ }
+ else
+ {
+ doc[scanDone] = true;
+ WiFi.scanDelete();
+ timeout = 0;
+ }
+ serializeJson(doc, result);
+ serverWeb.send(HTTP_CODE_OK, contTypeJson, result);
+}
+
+static void apiGetPage()
+{
+ if (!serverWeb.arg(argPage).length())
+ {
+ LOGW("wrong arg 'page' %s", serverWeb.argName(1).c_str());
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, apiWrongArgs);
+ return;
+ }
+ switch (serverWeb.arg(argPage).toInt())
+ {
+ case API_PAGE_ROOT:
+ handleRoot();
+ // sendGzip(contTypeTextHtml, PAGE_ROOT_html_gz, PAGE_ROOT_html_gz_len);
+ sendGzipFromFS("/html/root.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_GENERAL:
+ handleGeneral();
+ // sendGzip(contTypeTextHtml, PAGE_GENERAL_html_gz, PAGE_GENERAL_html_gz_len);
+ sendGzipFromFS("/html/general.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_NETWORK:
+ handleNetwork();
+ // sendGzip(contTypeTextHtml, PAGE_NETWORK_html_gz, PAGE_NETWORK_html_gz_len);
+ sendGzipFromFS("/html/network.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_ZIGBEE:
+ handleSerial();
+ // sendGzip(contTypeTextHtml, PAGE_ZIGBEE_html_gz, PAGE_ZIGBEE_html_gz_len);
+ sendGzipFromFS("/html/zigbee.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_SECURITY:
+ handleSecurity();
+ // sendGzip(contTypeTextHtml, PAGE_SECURITY_html_gz, PAGE_SECURITY_html_gz_len);
+ sendGzipFromFS("/html/security.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_TOOLS:
+ handleTools();
+ // sendGzip(contTypeTextHtml, PAGE_TOOLS_html_gz, PAGE_TOOLS_html_gz_len);
+ sendGzipFromFS("/html/tools.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_ABOUT:
+ // handleAbout();
+ // sendGzip(contTypeTextHtml, PAGE_ABOUT_html_gz, PAGE_ABOUT_html_gz_len);
+ sendGzipFromFS("/html/about.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_MQTT:
+ handleMqtt();
+ // sendGzip(contTypeTextHtml, PAGE_MQTT_html_gz, PAGE_MQTT_html_gz_len);
+ sendGzipFromFS("/html/mqtt.html.gz", contTypeTextHtml);
+ break;
+ case API_PAGE_VPN:
+ handleVpn();
+ // sendGzip(contTypeTextHtml, PAGE_VPN_html_gz, PAGE_VPN_html_gz_len);
+ sendGzipFromFS("/html/vpn.html.gz", contTypeTextHtml);
+ break;
+ default:
+ break;
+ }
+}
+
+static void apiGetFileList()
+{
+ String fileList = "";
+ DynamicJsonDocument doc(512);
+ JsonArray files = doc.createNestedArray("files");
+
+ // Открываем корневую директорию
+ File root = LittleFS.open("/");
+ File file = root.openNextFile();
+ while (file)
+ {
+ JsonObject jsonfile = files.createNestedObject();
+ jsonfile["filename"] = String(file.name());
+ jsonfile["size"] = file.size();
+ file.close(); // Закрываем файл после использования
+ file = root.openNextFile();
+ }
+ root.close(); // Закрываем корневую директорию
+
+ // Открываем директорию /x/
+ root = LittleFS.open("/x/");
+ file = root.openNextFile();
+ while (file)
+ {
+ JsonObject jsonfile = files.createNestedObject();
+ jsonfile["filename"] = String("/x/" + String(file.name()));
+ jsonfile["size"] = file.size();
+ file.close(); // Закрываем файл после использования
+ file = root.openNextFile();
+ }
+ root.close(); // Закрываем директорию /x/
+
+ serializeJson(doc, fileList);
+ serverWeb.send(HTTP_CODE_OK, contTypeJson, fileList);
+}
+
+static void apiDefault()
+{
+ LOGW("switch (action) err");
+}
+
+void handleApi()
+{
+ // Example api invocation:
+ // http://xzg.local/api?action=0&page=0
+
+ // apiFunctions[] will need to correspond to the
+ // values set in the JS frontend for "action"
+ static void (*apiFunctions[])() = {
+ apiDefault,
+ apiGetPage,
+ apiGetParam,
+ apiStartWifiScan,
+ apiWifiScanStatus,
+ apiGetFileList,
+ apiGetFile,
+ apiDefault, // invoked by what was previously API_SEND_HEX.
+ apiWifiConnnectStat,
+ apiCmd,
+ apiGetLog,
+ apiDelFile};
+ constexpr int numFunctions = sizeof(apiFunctions) / sizeof(apiFunctions[0]);
+ if (!is_authenticated())
+ {
+ redirectLogin(1);
+ return;
+ }
+ if (serverWeb.argName(0) == argAction)
+ {
+ // I add 1 to allow 0 to be default+overflow/invalid case.
+ // Ideally, the client would send 1-indexed "action"s
+ // but then I'd need to modify this in ALL of the client code...
+ const uint8_t action = serverWeb.arg(argAction).toInt() + 1;
+ const bool boundsCheck = action < numFunctions;
+ apiFunctions[action * boundsCheck]();
+ }
+ else
+ {
+ serverWeb.send(HTTP_CODE_INTERNAL_SERVER_ERROR, contTypeText, apiWrongArgs);
+ }
+}
+
+void handleSaveParams()
+{
+ if (!is_authenticated())
+ return;
+ updateConfiguration(serverWeb, systemCfg, networkCfg, vpnCfg, mqttCfg);
+}
+
+void printEachKeyValuePair(const String &jsonString)
+{
+ DynamicJsonDocument doc(1024);
+ DeserializationError error = deserializeJson(doc, jsonString);
+
+ if (error)
+ {
+
+ return;
+ }
+
+ const uint8_t eventLen = 100;
+
+ for (JsonPair kv : doc.as())
+ {
+ DynamicJsonDocument pairDoc(256);
+ pairDoc[kv.key().c_str()] = kv.value();
String output;
serializeJson(pairDoc, output);
@@ -903,6 +1226,7 @@ void updateWebTask(void *parameter)
{
String root_data = getRootData(true);
printEachKeyValuePair(root_data);
+ root_data = String(); // free memory
vTaskDelayUntil(&lastWakeTime, pdMS_TO_TICKS(systemCfg.refreshLogs * 1000));
}
}
@@ -912,14 +1236,15 @@ void handleLoginGet()
if (!is_authenticated())
{
// LOGD("handleLoginGet !is_authenticated");
- sendGzip(contTypeTextHtml, PAGE_LOGIN_html_gz, PAGE_LOGIN_html_gz_len);
+ // sendGzip(contTypeTextHtml, PAGE_LOGIN_html_gz, PAGE_LOGIN_html_gz_len);
+ sendGzipFromFS("/html/login.html.gz", contTypeTextHtml);
}
else
{
// LOGD("handleLoginGet else");
serverWeb.sendHeader("Location", "/");
serverWeb.sendHeader("Cache-Control", "no-cache");
- serverWeb.send(301);
+ serverWeb.send(HTTP_CODE_MOVED_PERMANENTLY);
// sendGzip(contTypeTextHtml, PAGE_LOADER_html_gz, PAGE_LOADER_html_gz_len);
}
}
@@ -948,7 +1273,7 @@ void handleLoginPost()
String token = sha1(String(systemCfg.webUser) + ":" + String(systemCfg.webPass) + ":" + serverWeb.client().remoteIP().toString());
serverWeb.sendHeader("Set-Cookie", "XZG_UID=" + token);
- serverWeb.send(301);
+ serverWeb.send(HTTP_CODE_MOVED_PERMANENTLY);
// Serial.println("Log in Successful");
return;
}
@@ -1003,11 +1328,11 @@ void handleGeneral()
String result;
doc[hwBtnIsKey] = vars.hwBtnIs;
- doc[hwUartSelIsKey] = vars.hwUartSelIs;
+ // doc[hwUartSelIsKey] = vars.hwUartSelIs;
doc[hwLedPwrIsKey] = vars.hwLedPwrIs;
doc[hwLedUsbIsKey] = vars.hwLedUsbIs;
- switch (systemCfg.workMode)
+ /*switch (systemCfg.workMode)
{
case WORK_MODE_USB:
doc["checkedUsbMode"] = checked;
@@ -1022,7 +1347,7 @@ void handleGeneral()
if (systemCfg.keepWeb)
{
doc[keepWebKey] = checked;
- }
+ }*/
if (systemCfg.disableLedPwr)
{
@@ -1050,10 +1375,17 @@ void handleGeneral()
doc[nmEnableKey] = checked;
}
+ if (systemCfg.updAutoInst)
+ {
+ doc[updAutoInstKey] = checked;
+ }
+ doc[updCheckTimeKey] = systemCfg.updCheckTime;
+ doc[updCheckDayKey] = systemCfg.updCheckDay;
+
serializeJson(doc, result);
serverWeb.sendHeader(respHeaderName, result);
- DynamicJsonDocument zones(10240);
+ DynamicJsonDocument zones(8000);
String results;
JsonArray zonesArray = zones.to();
@@ -1062,6 +1394,9 @@ void handleGeneral()
zonesArray.add(timeZones[i].zone);
}
+ // size_t usedMemory = zones.memoryUsage();
+ // LOGD("Zones used: %s bytes", String(usedMemory));
+
serializeJson(zones, results);
serverWeb.sendHeader(respTimeZonesName, results);
}
@@ -1086,7 +1421,8 @@ void handleSecurity()
{
doc[fwEnabledKey] = checked;
}
- doc[fwIpKey] = systemCfg.fwIp; //.toString();
+ doc[fwIpKey] = systemCfg.fwIp; //.toString();
+ doc[fwMaskKey] = systemCfg.fwMask; //.toString();
serializeJson(doc, result);
serverWeb.sendHeader(respHeaderName, result);
@@ -1130,6 +1466,68 @@ void handleNetwork()
doc[wifiDns1Key] = networkCfg.wifiDns1;
doc[wifiDns2Key] = networkCfg.wifiDns2;
+ switch (networkCfg.wifiMode)
+ {
+ case WIFI_PROTOCOL_11B:
+ doc["1"] = checked;
+ break;
+ case WIFI_PROTOCOL_11G:
+ doc["2"] = checked;
+ break;
+ case WIFI_PROTOCOL_11N:
+ doc["4"] = checked;
+ break;
+ case WIFI_PROTOCOL_LR:
+ doc["8"] = checked;
+ break;
+ default:
+ break;
+ }
+
+ switch (networkCfg.wifiPower)
+ {
+ case WIFI_POWER_19_5dBm:
+ doc["78"] = checked;
+ break;
+ case WIFI_POWER_19dBm:
+ doc["76"] = checked;
+ break;
+ case WIFI_POWER_18_5dBm:
+ doc["74"] = checked;
+ break;
+ case WIFI_POWER_17dBm:
+ doc["68"] = checked;
+ break;
+ case WIFI_POWER_15dBm:
+ doc["60"] = checked;
+ break;
+ case WIFI_POWER_13dBm:
+ doc["52"] = checked;
+ break;
+ case WIFI_POWER_11dBm:
+ doc["44"] = checked;
+ break;
+ case WIFI_POWER_8_5dBm:
+ doc["34"] = checked;
+ break;
+ case WIFI_POWER_7dBm:
+ doc["28"] = checked;
+ break;
+ case WIFI_POWER_5dBm:
+ doc["20"] = checked;
+ break;
+ case WIFI_POWER_2dBm:
+ doc["8"] = checked;
+ break;
+ default:
+ break;
+ }
+
+ if (hwConfig.eth.mdcPin == -1 || hwConfig.eth.mdiPin == -1)
+ {
+ doc["no_eth"] = 1;
+ }
+
serializeJson(doc, result);
serverWeb.sendHeader(respHeaderName, result);
}
@@ -1139,31 +1537,48 @@ void handleSerial()
String result;
DynamicJsonDocument doc(1024);
- if (systemCfg.serialSpeed == 9600)
+ switch (systemCfg.workMode)
{
- doc["9600"] = checked;
+ case WORK_MODE_USB:
+ doc["usbMode"] = checked;
+ break;
+ case WORK_MODE_NETWORK:
+ doc["lanMode"] = checked;
+ break;
+ default:
+ break;
}
- else if (systemCfg.serialSpeed == 19200)
+
+ switch (systemCfg.serialSpeed)
{
+ case 9600:
+ doc["9600"] = checked;
+ break;
+ case 19200:
doc["19200"] = checked;
- }
- else if (systemCfg.serialSpeed == 38400)
- {
- doc["8400"] = checked;
- }
- else if (systemCfg.serialSpeed == 57600)
- {
+ break;
+ case 38400:
+ doc["38400"] = checked;
+ break;
+ case 57600:
doc["57600"] = checked;
- }
- else if (systemCfg.serialSpeed == 115200)
- {
+ break;
+ case 115200:
doc["115200"] = checked;
- }
- else
- {
+ break;
+ case 230400:
+ doc["230400"] = checked;
+ break;
+ case 460800:
+ doc["460800"] = checked;
+ break;
+ default:
doc["115200"] = checked;
+ break;
}
+
doc[socketPortKey] = String(systemCfg.socketPort);
+ doc[zbRoleKey] = systemCfg.zbRole;
serializeJson(doc, result);
serverWeb.sendHeader(respHeaderName, result);
@@ -1232,41 +1647,10 @@ void handleVpn()
serverWeb.sendHeader(respHeaderName, result);
}
-String getRootData(bool update)
+static void getRootEthTab(DynamicJsonDocument &doc,
+ bool update,
+ const String &noConn)
{
- String tag = "root_data";
- DynamicJsonDocument doc(2048);
-
- String readableTime;
- getReadableTime(readableTime, vars.socketTime);
- const char *connectedSocketStatus = "connectedSocketStatus";
- const char *connectedSocket = "connectedSocket";
- const char *noConn = "noConn";
-
- doc[connectedSocketStatus] = vars.connectedClients;
- doc[connectedSocket] = vars.socketTime;
- doc["localTime"] = getTime();
-
- if (!update)
- {
- char verArr[25];
- const char *env = STRINGIFY(BUILD_ENV_NAME);
-
- if (strcasestr(env, "debug") != NULL)
- {
- sprintf(verArr, "%s (%s)", VERSION, env);
- }
- else
- {
- sprintf(verArr, "%s", VERSION);
- }
-
- doc["VERSION"] = String(verArr);
-
- const char *operationalMode = "operationalMode";
- doc[operationalMode] = systemCfg.workMode;
- }
-
// ETHERNET TAB
const char *ethConn = "ethConn";
const char *ethMac = "ethMac";
@@ -1287,7 +1671,9 @@ String getRootData(bool update)
doc[ethIpKey] = ETH.localIP().toString();
doc[ethMaskKey] = ETH.subnetMask().toString();
doc[ethGateKey] = ETH.gatewayIP().toString();
- doc[ethDns] = ETH.dnsIP().toString();
+ doc[ethDns] = ETH.dnsIP().toString(); // vars.savedEthDNS.toString(); // ETH.dnsIP().toString();
+ if (vars.ethIPv6)
+ doc[ethIPv6Key] = getShortenedIPv6(ETH.localIPv6().toString());
}
else
{
@@ -1295,72 +1681,59 @@ String getRootData(bool update)
doc[ethIpKey] = networkCfg.ethDhcp ? noConn : ETH.localIP().toString();
doc[ethMaskKey] = networkCfg.ethDhcp ? noConn : ETH.subnetMask().toString();
doc[ethGateKey] = networkCfg.ethDhcp ? noConn : ETH.gatewayIP().toString();
- doc[ethDns] = networkCfg.ethDhcp ? noConn : ETH.dnsIP().toString();
+ doc[ethDns] = networkCfg.ethDhcp ? noConn : ETH.dnsIP().toString(); // vars.savedEthDNS.toString(); // ETH.dnsIP().toString();
+ doc[ethIPv6Key] = noConn;
}
}
+}
- doc["uptime"] = millis(); // readableTime;
-
- float CPUtemp = getCPUtemp();
- doc["deviceTemp"] = String(CPUtemp);
+static inline void getRootWifi(DynamicJsonDocument &doc,
+ bool update,
+ const String &noConn)
+{
+ const char *wifiRssi = "wifiRssi";
+ const char *wifiConn = "wifiConn";
+ const char *wifiMode = "wifiMode";
+ const char *wifiDns = "wifiDns";
if (!update)
{
- doc["hwRev"] = hwConfig.board;
- doc["espModel"] = String(ESP.getChipModel());
- doc["espCores"] = ESP.getChipCores();
- doc["espFreq"] = ESP.getCpuFreqMHz();
-
- esp_chip_info_t chip_info;
- esp_chip_info(&chip_info);
-
- const char *espFlashType = "espFlashType";
- if (chip_info.features & CHIP_FEATURE_EMB_FLASH)
- {
- doc[espFlashType] = 1;
- }
- else
+ doc["wifiMac"] = WiFi.macAddress();
+ String boardStr = hwConfig.board;
+ if (boardStr.startsWith("Multi"))
{
- doc[espFlashType] = 2;
- }
-
- doc["espFlashSize"] = ESP.getFlashChipSize() / (1024 * 1024);
-
- doc["zigbeeFwRev"] = String(CCTool.chip.fwRev);
-
- doc["zigbeeHwRev"] = CCTool.chip.hwRev;
-
- doc["zigbeeIeee"] = CCTool.chip.ieee;
-
- doc["zigbeeFlSize"] = String(CCTool.chip.flashSize / 1024);
-
- unsigned int totalFs = LittleFS.totalBytes() / 1024;
- unsigned int usedFs = LittleFS.usedBytes() / 1024;
+ int underscoreIndex = boardStr.indexOf('_');
+ if (underscoreIndex != -1)
+ {
+ String boardNumber = boardStr.substring(underscoreIndex + 1);
+ boardNumber.trim();
+ const int boardNum = boardNumber.toInt();
- doc["espFsSize"] = totalFs;
- doc["espFsUsed"] = usedFs;
- }
- int heapSize = ESP.getHeapSize() / 1024;
- int heapFree = ESP.getFreeHeap() / 1024;
+ String boardArray[BOARD_CFG_CNT];
+ int arrayIndex = 0;
- doc["espHeapSize"] = heapSize;
- doc["espHeapUsed"] = heapSize - heapFree;
+ for (int brdNewIdx = 0; brdNewIdx < BOARD_CFG_CNT; brdNewIdx++)
+ {
+ if (brdConfigs[brdNewIdx].ethConfigIndex == brdConfigs[boardNum].ethConfigIndex && brdConfigs[brdNewIdx].zbConfigIndex == brdConfigs[boardNum].zbConfigIndex && brdConfigs[brdNewIdx].mistConfigIndex == brdConfigs[boardNum].mistConfigIndex)
+ {
+ boardArray[arrayIndex++] = brdConfigs[brdNewIdx].board;
+ }
+ }
- int total, used;
- getNvsStats(&total, &used);
+ DynamicJsonDocument jsonDoc(512);
+ JsonArray jsonArray = jsonDoc.to();
- doc["espNvsSize"] = total;
- doc["espNvsUsed"] = used;
+ for (int i = 0; i < arrayIndex; i++)
+ {
+ jsonArray.add(boardArray[i]);
+ }
- // wifi
- const char *wifiRssi = "wifiRssi";
- const char *wifiConn = "wifiConn";
- const char *wifiMode = "wifiMode";
- const char *wifiDns = "wifiDns";
+ String jsonString;
+ serializeJson(jsonArray, jsonString);
- if (!update)
- {
- doc["wifiMac"] = WiFi.macAddress();
+ doc["boardArray"] = jsonString;
+ }
+ }
}
if (networkCfg.wifiEnable)
@@ -1375,7 +1748,8 @@ String getRootData(bool update)
doc[wifiIpKey] = WiFi.localIP().toString();
doc[wifiMaskKey] = WiFi.subnetMask().toString();
doc[wifiGateKey] = WiFi.gatewayIP().toString();
- doc[wifiDns] = WiFi.dnsIP().toString();
+ doc[wifiDns] = WiFi.dnsIP().toString(); // vars.savedWifiDNS.toString(); // WiFi.dnsIP().toString();
+ doc[wifiIPv6Key] = WiFi.localIPv6().toString();
}
else
{
@@ -1385,7 +1759,7 @@ String getRootData(bool update)
doc[wifiIpKey] = networkCfg.wifiDhcp ? noConn : WiFi.localIP().toString();
doc[wifiMaskKey] = networkCfg.wifiDhcp ? noConn : WiFi.subnetMask().toString();
doc[wifiGateKey] = networkCfg.wifiDhcp ? noConn : WiFi.gatewayIP().toString();
- doc[wifiDns] = networkCfg.wifiDhcp ? noConn : WiFi.dnsIP().toString();
+ doc[wifiDns] = networkCfg.wifiDhcp ? noConn : WiFi.dnsIP().toString(); // vars.savedWifiDNS.toString(); // WiFi.dnsIP().toString();
}
}
@@ -1403,19 +1777,22 @@ String getRootData(bool update)
doc[wifiMode] = 2; //"AP";
doc[wifiRssi] = noConn; //"N/A";
}
+}
- // MQTT
+static inline void getRootMqtt(DynamicJsonDocument &doc)
+{
if (mqttCfg.enable)
{
const char *mqConnect = "mqConnect";
const char *mqBroker = "mqBroker";
doc[mqBroker] = mqttCfg.server;
-
doc[mqConnect] = vars.mqttConn ? 1 : 0;
}
+}
- // VPN WireGuard
+static inline void getRootVpnWireGuard(DynamicJsonDocument &doc)
+{
if (vpnCfg.wgEnable)
{
const char *wgInit = "wgInit";
@@ -1428,13 +1805,14 @@ String getRootData(bool update)
doc[wgInit] = vars.vpnWgInit ? 1 : 0;
doc[wgDeviceAddr] = vpnCfg.wgLocalIP.toString();
doc[wgRemoteAddr] = vpnCfg.wgEndAddr;
- // doc[wgEndPort] = vpnCfg.wgEndPort;
-
doc[wgConnect] = vars.vpnWgConnect ? 1 : 0;
-
doc[wgRemoteIP] = vars.vpnWgPeerIp.toString();
+ // doc[wgEndPort] = vpnCfg.wgEndPort;
}
- // VPN Husarnet
+}
+
+static inline void getRootVpnHusarnet(DynamicJsonDocument &doc)
+{
if (vpnCfg.hnEnable)
{
const char *hnInit = "hnInit";
@@ -1442,9 +1820,154 @@ String getRootData(bool update)
// doc[wgDeviceAddr] = vpnCfg.wgLocalIP.toString();//WgSettings.localAddr;
doc[hnHostName] = vpnCfg.hnHostName;
-
doc[hnInit] = vars.vpnHnInit ? 1 : 0;
}
+}
+
+static inline void getRootUptime(DynamicJsonDocument &doc)
+{
+ doc["uptime"] = millis(); // readableTime;
+}
+
+static inline void getRootCpuTemp(DynamicJsonDocument &doc)
+{
+ float CPUtemp = getCPUtemp();
+ doc["deviceTemp"] = String(CPUtemp);
+}
+
+static inline void getRootOneWireTemp(DynamicJsonDocument &doc)
+{
+ if (vars.oneWireIs)
+ {
+ float temp = get1wire();
+ doc["1wTemp"] = String(temp);
+ }
+}
+
+// Some misc hardware info,
+// maybe organise this more
+static inline void getRootHwMisc(DynamicJsonDocument &doc, bool update)
+{
+ if (update)
+ {
+ return;
+ }
+ char verArr[25];
+ const char *env = STRINGIFY(BUILD_ENV_NAME);
+
+ if (strcasestr(env, "debug") != NULL)
+ {
+ sprintf(verArr, "%s (%s)", VERSION, env);
+ }
+ else
+ {
+ sprintf(verArr, "%s", VERSION);
+ }
+
+ doc["VERSION"] = String(verArr);
+
+ const char *operationalMode = "operationalMode";
+ doc[operationalMode] = systemCfg.workMode;
+
+ doc[espUpdAvailKey] = vars.updateEspAvail;
+ doc[rcpUpdAvailKey] = vars.updateZbAvail;
+
+ doc["hwRev"] = hwConfig.board;
+ doc["espModel"] = String(ESP.getChipModel());
+ doc["espCores"] = ESP.getChipCores();
+ doc["espFreq"] = ESP.getCpuFreqMHz();
+
+ // esp_chip_info_t chip_info;
+ // esp_chip_info(&chip_info);
+
+ const char *espFlashType = "espFlashType";
+ if (true) // chip_info.features & CHIP_FEATURE_EMB_FLASH)
+ {
+ doc[espFlashType] = 1;
+ }
+ else
+ {
+ doc[espFlashType] = 2;
+ }
+
+ doc["espFlashSize"] = ESP.getFlashChipSize() / (1024 * 1024);
+
+ // doc["zigbeeFwRev"] = String(CCTool.chip.fwRev);
+ if (CCTool.chip.fwRev > 0)
+ {
+ doc["zigbeeFwRev"] = String(CCTool.chip.fwRev);
+ }
+ else
+ {
+ doc["zigbeeFwRev"] = String(systemCfg.zbFw);
+ doc["zbFwSaved"] = true;
+ }
+
+ doc["zigbeeHwRev"] = CCTool.chip.hwRev;
+ doc["zigbeeIeee"] = CCTool.chip.ieee;
+ doc["zigbeeFlSize"] = String(CCTool.chip.flashSize / 1024);
+
+ unsigned int totalFs = LittleFS.totalBytes() / 1024;
+ unsigned int usedFs = LittleFS.usedBytes() / 1024;
+ doc["espFsSize"] = totalFs;
+ doc["espFsUsed"] = usedFs;
+
+ doc[zbRoleKey] = systemCfg.zbRole;
+ doc["zigbeeFwSaved"] = systemCfg.zbFw;
+}
+
+static inline void getRootHeapsize(DynamicJsonDocument &doc)
+{
+ int heapSize = ESP.getHeapSize() / 1024;
+ int heapFree = ESP.getFreeHeap() / 1024;
+
+ doc["espHeapSize"] = heapSize;
+ doc["espHeapUsed"] = heapSize - heapFree;
+}
+
+static inline void getRootNvsStats(DynamicJsonDocument &doc)
+{
+ int total, used;
+ getNvsStats(&total, &used);
+
+ doc["espNvsSize"] = total;
+ doc["espNvsUsed"] = used;
+}
+
+static inline void getRootSockets(DynamicJsonDocument &doc)
+{
+ const char *connectedSocketStatus = "connectedSocketStatus";
+ const char *connectedSocket = "connectedSocket";
+
+ doc[connectedSocketStatus] = vars.connectedClients;
+ doc[connectedSocket] = vars.socketTime;
+}
+
+static inline void getRootTime(DynamicJsonDocument &doc)
+{
+ doc["localTime"] = getTime();
+}
+
+String getRootData(bool update)
+{
+ DynamicJsonDocument doc(2048);
+
+ const char *noConn = "noConn";
+ getRootEthTab(doc, update, noConn);
+ getRootWifi(doc, update, noConn);
+
+ getRootHwMisc(doc, update);
+
+ getRootSockets(doc);
+ getRootTime(doc);
+ getRootUptime(doc);
+ getRootCpuTemp(doc);
+ getRootOneWireTemp(doc);
+ getRootHeapsize(doc);
+ getRootNvsStats(doc);
+ getRootMqtt(doc);
+ getRootVpnWireGuard(doc);
+ getRootVpnHusarnet(doc);
String result;
serializeJson(doc, result);
@@ -1464,11 +1987,11 @@ void handleTools()
DynamicJsonDocument doc(512);
doc[hwBtnIsKey] = vars.hwBtnIs;
- doc[hwUartSelIsKey] = vars.hwUartSelIs;
doc[hwLedPwrIsKey] = vars.hwLedPwrIs;
doc[hwLedUsbIsKey] = vars.hwLedUsbIs;
- // doc["hostname"] = systemCfg.hostname;
- // doc["refreshLogs"] = systemCfg.refreshLogs;
+ // doc[hwUartSelIsKey] = vars.hwUartSelIs;
+ // doc["hostname"] = systemCfg.hostname;
+ // doc["refreshLogs"] = systemCfg.refreshLogs;
serializeJson(doc, result);
serverWeb.sendHeader(respHeaderName, result);
@@ -1487,6 +2010,7 @@ void handleSavefile()
String filename = "/" + serverWeb.arg(0);
String content = serverWeb.arg(1);
File file = LittleFS.open(filename, "w");
+
LOGD("try %s", filename.c_str());
if (!file)
@@ -1494,7 +2018,6 @@ void handleSavefile()
LOGW("Failed to open file for reading");
return;
}
-
int bytesWritten = file.print(content);
if (bytesWritten > 0)
{
@@ -1514,7 +2037,6 @@ void handleSavefile()
/* ----- Multi-tool support | START -----*/
void handleZigbeeBSL()
{
-
zigbeeEnableBSL();
serverWeb.send(HTTP_CODE_OK, contTypeText, "Zigbee BSL");
}
@@ -1552,16 +2074,16 @@ void printLogMsg(String msg)
logPush('\n');
LOGI("%s", msg.c_str());
}
-
+/*
void progressNvRamFunc(unsigned int progress, unsigned int total)
{
- const char *tagESP_FW_progress = "ESP_FW_prgs";
+ const char *tagESP_FW_prgs = "ESP_FW_prgs";
const uint8_t eventLen = 11;
float percent = ((float)progress / total) * 100.0;
- sendEvent(tagESP_FW_progress, eventLen, String(percent));
+ sendEvent(tagESP_FW_prgs, eventLen, String(percent));
// printLogMsg(String(percent));
#ifdef DEBUG
@@ -1571,22 +2093,22 @@ void progressNvRamFunc(unsigned int progress, unsigned int total)
}
#endif
};
+*/
void progressFunc(unsigned int progress, unsigned int total)
{
- const char *tagESP_FW_progress = "ESP_FW_prgs";
const uint8_t eventLen = 11;
float percent = ((float)progress / total) * 100.0;
- sendEvent(tagESP_FW_progress, eventLen, String(percent));
+ sendEvent(tagESP_FW_prgs, eventLen, String(percent));
// printLogMsg(String(percent));
#ifdef DEBUG
if (int(percent) % 5 == 0)
{
- LOGD("Update ESP32 progress: %s of %s | %s%", String(progress), String(total), String(percent));
+ LOGD("Update ESP32 progress: %s of %s | %s%%", String(progress).c_str(), String(total).c_str(), String(percent).c_str());
}
#endif
};
@@ -1598,55 +2120,77 @@ void getEspUpdate(String esp_fw_url)
{
LOGI("getEspUpdate: %s", esp_fw_url.c_str());
- HTTPClient clientWeb;
- WiFiClientSecure client;
- client.setInsecure(); // the magic line, use with caution
- clientWeb.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
- clientWeb.begin(client, esp_fw_url);
- clientWeb.addHeader("Content-Type", "application/octet-stream");
-
- // Get file, just to check if each reachable
- int resp = clientWeb.GET();
- LOGD("Response: %s", String(resp));
- // If file is reachable, start downloading
- if (resp == HTTP_CODE_OK)
- {
- // get length of document (is -1 when Server sends no Content-Length header)
- totalLength = clientWeb.getSize();
- // transfer to local variable
- int len = totalLength;
- // this is required to start firmware update process
- Update.begin(totalLength);
- Update.onProgress(progressFunc);
- LOGI("FW Size: %s", String(totalLength));
- // create buffer for read
- uint8_t buff[128] = {0};
- // get tcp stream
- WiFiClient *stream = clientWeb.getStreamPtr();
- // read all data from server
- LOGI("Updating firmware...");
- while (clientWeb.connected() && (len > 0 || len == -1))
+ // checkDNS();
+ HTTPClient http;
+ // WiFiClientSecure client;
+ // client.setInsecure(); // the magic line, use with caution
+ http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
+ // http.begin(client, esp_fw_url);
+
+ if (dnsLookup(esp_fw_url))
+ {
+ http.begin(esp_fw_url);
+ http.addHeader("Content-Type", "application/octet-stream");
+
+ // Get file, just to check if each reachable
+ int resp = http.GET();
+ LOGD("Response: %s", String(resp).c_str());
+ // If file is reachable, start downloading
+ if (resp == HTTP_CODE_OK)
{
- // get available data size
- size_t size = stream->available();
- if (size)
+ // get length of document (is -1 when Server sends no Content-Length header)
+ totalLength = http.getSize();
+ // transfer to local variable
+ int len = totalLength;
+ // this is required to start firmware update process
+
+ int updateType = 0;
+ bool isSpiffsUpdate = false;
+ if (esp_fw_url.endsWith(".fs.bin"))
+
{
- // read up to 128 byte
- int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
- // pass to function
- runEspUpdateFirmware(buff, c);
- if (len > 0)
+ updateType = U_SPIFFS;
+ isSpiffsUpdate = true;
+ }
+ else
+ {
+ updateType = U_FLASH;
+ isSpiffsUpdate = false;
+ }
+
+ Update.begin(totalLength, updateType);
+ Update.onProgress(progressFunc);
+ LOGI("File size: %s", String(totalLength).c_str());
+ // create buffer for read
+ uint8_t buff[128] = {0};
+ // get tcp stream
+ WiFiClient *stream = http.getStreamPtr();
+ // read all data from server
+ LOGI("Updating %s ...", isSpiffsUpdate ? "file system" : "firmware");
+ while (http.connected() && (len > 0 || len == -1))
+ {
+ esp_task_wdt_reset();
+ // get available data size
+ size_t size = stream->available();
+ if (size)
{
- len -= c;
+ // read up to 128 byte
+ int c = stream->readBytes(buff, ((size > sizeof(buff)) ? sizeof(buff) : size));
+ // pass to function
+ runEspUpdateFirmware(buff, c);
+ if (len > 0)
+ {
+ len -= c;
+ }
}
}
}
+ else
+ {
+ LOGI("Cannot download firmware file.");
+ }
+ http.end();
}
- else
- {
- LOGI("Cannot download firmware file.");
- }
- clientWeb.end();
}
void runEspUpdateFirmware(uint8_t *data, size_t len)
@@ -1661,13 +2205,87 @@ void runEspUpdateFirmware(uint8_t *data, size_t len)
Update.end(true);
LOGD("Update success. Rebooting...");
// Restart ESP32 to see changes
- ESP.restart();
+ restartDevice();
+}
+
+FirmwareInfo fetchLatestEspFw(String type)
+{
+ FirmwareInfo info = {"", ""};
+
+ if (type == "fs" || type == "ota")
+ {
+ HTTPClient http;
+ http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
+ http.begin("https://raw.githubusercontent.com/xyzroe/XZG/refs/heads/releases/latest/xzg.json");
+ int httpCode = http.GET();
+
+ if (httpCode > 0)
+ {
+ String payload = http.getString();
+
+ DynamicJsonDocument doc(4096);
+ DeserializationError error = deserializeJson(doc, payload);
+
+ if (!error)
+ {
+ size_t usedMemory = doc.memoryUsage();
+ LOGD("doc used: %s bytes", String(usedMemory).c_str());
+
+ JsonObject release = doc.as();
+
+ if (release.containsKey("version"))
+ {
+ info.version = release["version"].as();
+ info.url = "https://github.com/xyzroe/XZG/releases/download/" + info.version + "/XZG_" + info.version + "." + type + ".bin";
+ //info.url = "https://raw.githubusercontent.com/xyzroe/XZG/refs/heads/releases/latest/XZG." + type + ".bin";
+ LOGD("Latest version: %s | url %s", info.version.c_str(), info.url.c_str());
+ }
+ else
+ {
+ LOGD("No version found");
+ }
+
+ String needKey;
+ if (type == "fs")
+ {
+ needKey = "fs_sha";
+ }
+ else
+ {
+ needKey = "fw_sha";
+ }
+ if (release.containsKey(needKey))
+ {
+ info.sha = release[needKey].as();
+ }
+ else
+ {
+ LOGD("No SHA for %s found", type.c_str());
+ }
+ }
+ else
+ {
+ LOGD("deserializeJson failed: %s", error.c_str());
+ }
+ }
+ else
+ {
+ LOGD("Error on HTTP request: %d", httpCode);
+ }
+ http.end();
+ }
+ else
+ {
+ LOGD("Invalid type: %s", type.c_str());
+ }
+ return info;
}
-String fetchGitHubReleaseInfo()
+String fetchLatestZbFw()
{
+ // checkDNS();
HTTPClient http;
- http.begin("https://api.github.com/repos/xyzroe/xzg/releases");
+ http.begin("https://raw.githubusercontent.com/xyzroe/XZG/zb_fws/ti/manifest.json");
int httpCode = http.GET();
String browser_download_url = "";
@@ -1676,19 +2294,55 @@ String fetchGitHubReleaseInfo()
{
String payload = http.getString();
- DynamicJsonDocument doc(8192);
- deserializeJson(doc, payload);
- JsonArray releases = doc.as();
+ DynamicJsonDocument doc(8192 * 2);
+ DeserializationError error = deserializeJson(doc, payload);
+
+ if (error)
+ {
+ LOGD("deserializeJson() failed: %s", error.c_str());
+ return "";
+ }
+
+ size_t usedMemory = doc.memoryUsage();
+ LOGD("doc used: %s bytes", String(usedMemory).c_str());
+
+ String roleKey = getRadioRoleKey();
- if (releases.size() > 0 && releases[0]["assets"].size() > 1)
+ /*if (systemCfg.zbRole == COORDINATOR)
{
- browser_download_url = releases[0]["assets"][1]["browser_download_url"].as();
- LOGD("browser_download_url: %s", browser_download_url.c_str());
+ roleKey = "coordinator";
+ }
+ else if (systemCfg.zbRole == ROUTER)
+ {
+ roleKey = "router";
+ }
+ else if (systemCfg.zbRole == OPENTHREAD)
+ {
+ roleKey = "thread";
+ }*/
+
+ if (doc.containsKey(roleKey) && doc[roleKey].containsKey(CCTool.chip.hwRev))
+ {
+ JsonObject roleObj = doc[roleKey][CCTool.chip.hwRev].as();
+ for (JsonPair kv : roleObj)
+ {
+ JsonObject file = kv.value().as();
+ if (file.containsKey("link"))
+ {
+ browser_download_url = file["link"].as();
+ if (file.containsKey("baud"))
+ {
+ browser_download_url = browser_download_url + "?b=" + file["baud"].as();
+ }
+ break;
+ }
+ }
+ // LOGD("browser_download_url: %s", browser_download_url.c_str());
}
}
else
{
- LOGD("Error on HTTP request");
+ LOGD("Error on HTTP request: %d", httpCode);
}
http.end();
@@ -1697,8 +2351,13 @@ String fetchGitHubReleaseInfo()
String extractVersionFromURL(String url)
{
- int startPos = url.indexOf("/download/") + 10;
- int endPos = url.indexOf("/", startPos);
+ int startPos = url.lastIndexOf('_') + 1;
+ int endPos = url.indexOf(".ota.bin");
+ if (endPos == -1)
+ {
+ endPos = url.indexOf(".bin");
+ }
+
if (startPos != -1 && endPos != -1)
{
return url.substring(startPos, endPos);
diff --git a/src/web.h b/src/web.h
index b9bdce3a..b9fb0739 100644
--- a/src/web.h
+++ b/src/web.h
@@ -1,3 +1,8 @@
+#ifndef WEB_H
+#define WEB_H
+
+#include "etc.h" // Включение заголовочного файла etc.h
+
#include
void handleEvents();
void initWebServer();
@@ -23,7 +28,8 @@ void handleEspUpdateUpload();
void handleNotFound();
bool captivePortal();
-void sendGzip(const char* contentType, const uint8_t content[], uint16_t contentLen);
+//void sendGzip(const char* contentType, const uint8_t content[], uint16_t contentLen);
+void sendGzipFromFS(const char* path, const char* contentType);
void handleTools();
void printLogTime();
void printLogMsg(String msg);
@@ -36,7 +42,11 @@ void progressFunc(unsigned int progress, unsigned int total);
void getEspUpdate(String esp_fw_url);
void runEspUpdateFirmware(uint8_t *data, size_t len);
-String fetchGitHubReleaseInfo();
+
+
+
+FirmwareInfo fetchLatestEspFw(String type = "ota");
+String fetchLatestZbFw();
String extractVersionFromURL(String url);
void updateWebTask(void *parameter);
@@ -55,3 +65,5 @@ enum API_PAGE_t : uint8_t
API_PAGE_VPN,
};
+
+#endif // WEB_H
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_GENERAL.html b/src/websrc/html/PAGE_GENERAL.html
deleted file mode 100644
index 1b969ee6..00000000
--- a/src/websrc/html/PAGE_GENERAL.html
+++ /dev/null
@@ -1,160 +0,0 @@
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_LOADER.html b/src/websrc/html/PAGE_LOADER.html
deleted file mode 100644
index edef5850..00000000
--- a/src/websrc/html/PAGE_LOADER.html
+++ /dev/null
@@ -1,223 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
XZG
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_LOGIN.html b/src/websrc/html/PAGE_LOGIN.html
deleted file mode 100644
index 32d312ff..00000000
--- a/src/websrc/html/PAGE_LOGIN.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_MQTT.html b/src/websrc/html/PAGE_MQTT.html
deleted file mode 100644
index b496bc9a..00000000
--- a/src/websrc/html/PAGE_MQTT.html
+++ /dev/null
@@ -1,83 +0,0 @@
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_NETWORK.html b/src/websrc/html/PAGE_NETWORK.html
deleted file mode 100644
index e1a8016c..00000000
--- a/src/websrc/html/PAGE_NETWORK.html
+++ /dev/null
@@ -1,173 +0,0 @@
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_SECURITY.html b/src/websrc/html/PAGE_SECURITY.html
deleted file mode 100644
index 54396dab..00000000
--- a/src/websrc/html/PAGE_SECURITY.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_TOOLS.html b/src/websrc/html/PAGE_TOOLS.html
deleted file mode 100644
index af7c7a57..00000000
--- a/src/websrc/html/PAGE_TOOLS.html
+++ /dev/null
@@ -1,266 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_VPN.html b/src/websrc/html/PAGE_VPN.html
deleted file mode 100644
index 478ac325..00000000
--- a/src/websrc/html/PAGE_VPN.html
+++ /dev/null
@@ -1,106 +0,0 @@
-
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_ABOUT.html b/src/websrc/html/about.html
similarity index 59%
rename from src/websrc/html/PAGE_ABOUT.html
rename to src/websrc/html/about.html
index d5281de1..da9b5749 100644
--- a/src/websrc/html/PAGE_ABOUT.html
+++ b/src/websrc/html/about.html
@@ -1,20 +1,16 @@
-
+
-
-
-
+
-
-
@@ -22,12 +18,10 @@
-
-
-
+
-
-
-
\ No newline at end of file
diff --git a/src/websrc/html/general.html b/src/websrc/html/general.html
new file mode 100644
index 00000000..115698c5
--- /dev/null
+++ b/src/websrc/html/general.html
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/websrc/html/loader.html b/src/websrc/html/loader.html
new file mode 100644
index 00000000..4b0a8cd2
--- /dev/null
+++ b/src/websrc/html/loader.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
XZG
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/websrc/html/login.html b/src/websrc/html/login.html
new file mode 100644
index 00000000..8b571825
--- /dev/null
+++ b/src/websrc/html/login.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xyzroe © 2024
+
+
+
+
+
\ No newline at end of file
diff --git a/src/websrc/html/mqtt.html b/src/websrc/html/mqtt.html
new file mode 100644
index 00000000..6bf27268
--- /dev/null
+++ b/src/websrc/html/mqtt.html
@@ -0,0 +1,58 @@
+
\ No newline at end of file
diff --git a/src/websrc/html/network.html b/src/websrc/html/network.html
new file mode 100644
index 00000000..ac67a257
--- /dev/null
+++ b/src/websrc/html/network.html
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_ROOT.html b/src/websrc/html/root.html
similarity index 80%
rename from src/websrc/html/PAGE_ROOT.html
rename to src/websrc/html/root.html
index cb3d69b8..1a5706f3 100644
--- a/src/websrc/html/PAGE_ROOT.html
+++ b/src/websrc/html/root.html
@@ -1,13 +1,10 @@
-
-
@@ -23,6 +20,10 @@
+
+
+
+
@@ -37,12 +38,8 @@
-
-
-
-
+
-
@@ -50,11 +47,9 @@
-
@@ -77,18 +72,14 @@
-
- °C
-
+ °C
- @
-
-
-
+ @
@@ -97,9 +88,8 @@
-
@@ -107,8 +97,7 @@
,
-
+ data-r2v="espFlashType">
@@ -116,9 +105,8 @@
@@ -144,6 +130,17 @@
+
+
+
+
+
+
@@ -151,11 +148,9 @@
-
@@ -191,6 +186,10 @@
+
+
+
+
@@ -198,11 +197,9 @@
-
@@ -241,9 +238,7 @@
-
-
-
+
@@ -251,6 +246,12 @@
+
@@ -258,11 +259,9 @@
-
@@ -281,11 +280,9 @@
-
@@ -316,11 +313,9 @@
-
diff --git a/src/websrc/html/security.html b/src/websrc/html/security.html
new file mode 100644
index 00000000..35345981
--- /dev/null
+++ b/src/websrc/html/security.html
@@ -0,0 +1,61 @@
+
\ No newline at end of file
diff --git a/src/websrc/html/tools.html b/src/websrc/html/tools.html
new file mode 100644
index 00000000..91f0a246
--- /dev/null
+++ b/src/websrc/html/tools.html
@@ -0,0 +1,182 @@
+
\ No newline at end of file
diff --git a/src/websrc/html/vpn.html b/src/websrc/html/vpn.html
new file mode 100644
index 00000000..029719ae
--- /dev/null
+++ b/src/websrc/html/vpn.html
@@ -0,0 +1,73 @@
+
\ No newline at end of file
diff --git a/src/websrc/html/PAGE_ZIGBEE.html b/src/websrc/html/zigbee.html
similarity index 50%
rename from src/websrc/html/PAGE_ZIGBEE.html
rename to src/websrc/html/zigbee.html
index 70cbbb22..3ad1343e 100644
--- a/src/websrc/html/PAGE_ZIGBEE.html
+++ b/src/websrc/html/zigbee.html
@@ -1,39 +1,30 @@
-