Merge pull request #2674 from proddy/dev

use pio to update CSV files
This commit is contained in:
Proddy
2025-10-23 22:38:42 +02:00
committed by GitHub
24 changed files with 6728 additions and 6227 deletions

View File

@@ -18,17 +18,17 @@ jobs:
steps:
- name: Install python 3.13
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install Node.js 22
uses: actions/setup-node@v4
- name: Install Node.js 24
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable pnpm
@@ -45,20 +45,48 @@ jobs:
pip install -U platformio
python -m pip install intelhex
- name: Build the WebUI
- name: Build webUI
run: |
cd interface
pnpm install
pnpm typesafe-i18n --no-watch
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
pnpm build
pnpm webUI
platformio run -e build_webUI
- name: Build all PIO target environments
- name: Build modbus
run: |
platformio run -e build_modbus
- name: Build standalone
run: |
platformio run -e build_standalone
- name: Build all PIO target environments, from default_envs
run: |
platformio run
env:
NO_BUILD_WEBUI: true
- name: Commit the generated files
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: update generated files"
- name: Configure Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Check for changes and commit
run: |
if [ -n "$(git status --porcelain)" ]; then
echo "Changes detected, committing..."
git add .
git commit -m "Auto-commit build artifacts and configuration updates
- Updated build configurations
- Generated build artifacts
- Version: ${{steps.build_info.outputs.VERSION}}"
echo "Pushing changes to repository..."
git push origin dev
else
echo "No changes to commit"
fi
- name: Create GitHub Release
id: 'automatic_releases'

View File

@@ -20,12 +20,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install python 3.11
uses: actions/setup-python@v5
- name: Install python 3.13
uses: actions/setup-python@v6
with:
python-version: '3.11'
python-version: '3.13'
- name: Install PlatformIO
run: |

View File

@@ -17,7 +17,7 @@ jobs:
BUILD_WRAPPER_OUT_DIR: bw-output
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Install Build Wrapper

View File

@@ -16,17 +16,17 @@ jobs:
steps:
- name: Install python 3.13
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install Node.js 22
uses: actions/setup-node@v4
- name: Install Node.js 24
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable pnpm
@@ -37,20 +37,21 @@ jobs:
pip install -U platformio
python -m pip install intelhex
- name: Build the WebUI
- name: Build webUI
run: |
cd interface
pnpm install
pnpm typesafe-i18n --no-watch
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
pnpm build
pnpm webUI
platformio run -e build_webUI
- name: Build all PIO target environments
- name: Build modbus
run: |
platformio run -e build_modbus
- name: Build standalone
run: |
platformio run -e build_standalone
- name: Build all PIO target environments, from default_envs
run: |
platformio run
env:
NO_BUILD_WEBUI: true
- name: Create GitHub Release
uses: emsesp/action-automatic-releases@v1.0.0

View File

@@ -8,7 +8,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 30

View File

@@ -4,7 +4,7 @@ on:
workflow_dispatch:
push:
branches:
- 'dev2'
- 'test'
permissions:
contents: read
@@ -18,17 +18,17 @@ jobs:
steps:
- name: Install python 3.13
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: '3.13'
- name: Install Node.js 22
uses: actions/setup-node@v4
- name: Install Node.js 24
uses: actions/setup-node@v6
with:
node-version: 22
node-version: 24
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Enable Corepack
run: corepack enable pnpm
@@ -45,20 +45,21 @@ jobs:
pip install -U platformio
python -m pip install intelhex
- name: Build the WebUI
- name: Build webUI
run: |
cd interface
pnpm install
pnpm typesafe-i18n --no-watch
sed -i "s/= 'pl'/= 'en'/" ./src/i18n/i18n-util.ts
pnpm build
pnpm webUI
platformio run -e build_webUI
- name: Build all target environments
- name: Build modbus
run: |
platformio run -e build_modbus
- name: Build standalone
run: |
platformio run -e build_standalone
- name: Build all PIO target environments, from default_envs
run: |
platformio run
env:
NO_BUILD_WEBUI: true
- name: Create GitHub Release
id: 'automatic_releases'

2
.gitignore vendored
View File

@@ -72,3 +72,5 @@ CMakeLists.txt
logs/*
sdkconfig.*
sdkconfig_tasmota_esp32
pnpm-lock.yaml
package.json

View File

@@ -44,7 +44,7 @@
"typescript": "^5.9.3"
},
"devDependencies": {
"@babel/core": "^7.28.4",
"@babel/core": "^7.28.5",
"@eslint/js": "^9.38.0",
"@preact/compat": "^18.3.1",
"@preact/preset-vite": "^2.10.2",
@@ -59,7 +59,7 @@
"rollup-plugin-visualizer": "^6.0.5",
"terser": "^5.44.0",
"typescript-eslint": "^8.46.2",
"vite": "^7.1.11",
"vite": "^7.1.12",
"vite-plugin-imagemin": "^0.6.1",
"vite-tsconfig-paths": "^5.1.4"
},

182
interface/pnpm-lock.yaml generated
View File

@@ -70,8 +70,8 @@ importers:
version: 5.9.3
devDependencies:
'@babel/core':
specifier: ^7.28.4
version: 7.28.4
specifier: ^7.28.5
version: 7.28.5
'@eslint/js':
specifier: ^9.38.0
version: 9.38.0
@@ -80,7 +80,7 @@ importers:
version: 18.3.1(preact@10.27.2)
'@preact/preset-vite':
specifier: ^2.10.2
version: 2.10.2(@babel/core@7.28.4)(preact@10.27.2)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))
version: 2.10.2(@babel/core@7.28.5)(preact@10.27.2)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))
'@trivago/prettier-plugin-sort-imports':
specifier: ^5.2.2
version: 5.2.2(prettier@3.6.2)
@@ -115,14 +115,14 @@ importers:
specifier: ^8.46.2
version: 8.46.2(eslint@9.38.0)(typescript@5.9.3)
vite:
specifier: ^7.1.11
version: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
specifier: ^7.1.12
version: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
vite-plugin-imagemin:
specifier: ^0.6.1
version: 0.6.1(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))
version: 0.6.1(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))
vite-tsconfig-paths:
specifier: ^5.1.4
version: 5.1.4(typescript@5.9.3)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))
version: 5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))
packages:
@@ -138,16 +138,16 @@ packages:
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.28.4':
resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==}
'@babel/compat-data@7.28.5':
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
engines: {node: '>=6.9.0'}
'@babel/core@7.28.4':
resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==}
'@babel/core@7.28.5':
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.3':
resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-annotate-as-pure@7.27.3':
@@ -180,8 +180,8 @@ packages:
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.27.1':
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-option@7.27.1':
@@ -192,8 +192,8 @@ packages:
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.28.4':
resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
'@babel/parser@7.28.5':
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -223,12 +223,12 @@ packages:
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.28.4':
resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
'@babel/traverse@7.28.5':
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.28.4':
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
'@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
'@emotion/babel-plugin@11.13.5':
@@ -1014,8 +1014,8 @@ packages:
base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.8.19:
resolution: {integrity: sha512-zoKGUdu6vb2jd3YOq0nnhEDQVbPcHhco3UImJrv5dSkvxTc2pl2WjOPsjZXDwPDSl5eghIMuY3R6J9NDKF3KcQ==}
baseline-browser-mapping@2.8.20:
resolution: {integrity: sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==}
hasBin: true
bin-build@3.0.0:
@@ -2976,8 +2976,8 @@ packages:
vite:
optional: true
vite@7.1.11:
resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==}
vite@7.1.12:
resolution: {integrity: sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -3084,23 +3084,23 @@ snapshots:
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.28.4': {}
'@babel/compat-data@7.28.5': {}
'@babel/core@7.28.4':
'@babel/core@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.3
'@babel/generator': 7.28.5
'@babel/helper-compilation-targets': 7.27.2
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4)
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
'@babel/helpers': 7.28.4
'@babel/parser': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/traverse': 7.28.4
'@babel/types': 7.28.4
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3
@@ -3110,21 +3110,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@babel/generator@7.28.3':
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.4
'@babel/types': 7.28.4
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-annotate-as-pure@7.27.3':
dependencies:
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@babel/helper-compilation-targets@7.27.2':
dependencies:
'@babel/compat-data': 7.28.4
'@babel/compat-data': 7.28.5
'@babel/helper-validator-option': 7.27.1
browserslist: 4.27.0
lru-cache: 5.1.1
@@ -3134,17 +3134,17 @@ snapshots:
'@babel/helper-module-imports@7.27.1':
dependencies:
'@babel/traverse': 7.28.4
'@babel/types': 7.28.4
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)':
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.4
'@babel/core': 7.28.5
'@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/traverse': 7.28.4
'@babel/helper-validator-identifier': 7.28.5
'@babel/traverse': 7.28.5
transitivePeerDependencies:
- supports-color
@@ -3152,39 +3152,39 @@ snapshots:
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-option@7.27.1': {}
'@babel/helpers@7.28.4':
dependencies:
'@babel/template': 7.27.2
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@babel/parser@7.28.4':
'@babel/parser@7.28.5':
dependencies:
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)':
'@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.4
'@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.4)':
'@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.4)
'@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5)
transitivePeerDependencies:
- supports-color
'@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.4)':
'@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.4
'@babel/core': 7.28.5
'@babel/helper-annotate-as-pure': 7.27.3
'@babel/helper-module-imports': 7.27.1
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4)
'@babel/types': 7.28.4
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
@@ -3193,25 +3193,25 @@ snapshots:
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.4
'@babel/types': 7.28.4
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@babel/traverse@7.28.4':
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.3
'@babel/generator': 7.28.5
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.4
'@babel/types': 7.28.5
debug: 4.4.3
transitivePeerDependencies:
- supports-color
'@babel/types@7.28.4':
'@babel/types@7.28.5':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@emotion/babel-plugin@11.13.5':
dependencies:
@@ -3575,18 +3575,18 @@ snapshots:
dependencies:
preact: 10.27.2
'@preact/preset-vite@2.10.2(@babel/core@7.28.4)(preact@10.27.2)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))':
'@preact/preset-vite@2.10.2(@babel/core@7.28.5)(preact@10.27.2)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.4)
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.4)
'@prefresh/vite': 2.4.10(preact@10.27.2)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))
'@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5)
'@prefresh/vite': 2.4.10(preact@10.27.2)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))
'@rollup/pluginutils': 4.2.1
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.4)
babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.28.5)
debug: 4.4.3
picocolors: 1.1.1
vite: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
vite-prerender-plugin: 0.5.12(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))
vite: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
vite-prerender-plugin: 0.5.12(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))
transitivePeerDependencies:
- preact
- supports-color
@@ -3599,15 +3599,15 @@ snapshots:
'@prefresh/utils@1.2.1': {}
'@prefresh/vite@2.4.10(preact@10.27.2)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0))':
'@prefresh/vite@2.4.10(preact@10.27.2)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0))':
dependencies:
'@babel/core': 7.28.4
'@babel/core': 7.28.5
'@prefresh/babel-plugin': 0.5.2
'@prefresh/core': 1.5.8(preact@10.27.2)
'@prefresh/utils': 1.2.1
'@rollup/pluginutils': 4.2.1
preact: 10.27.2
vite: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
vite: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
@@ -3695,10 +3695,10 @@ snapshots:
'@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.6.2)':
dependencies:
'@babel/generator': 7.28.3
'@babel/parser': 7.28.4
'@babel/traverse': 7.28.4
'@babel/types': 7.28.4
'@babel/generator': 7.28.5
'@babel/parser': 7.28.5
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
javascript-natural-sort: 0.7.1
lodash: 4.17.21
prettier: 3.6.2
@@ -3928,15 +3928,15 @@ snapshots:
cosmiconfig: 7.1.0
resolve: 1.22.11
babel-plugin-transform-hook-names@1.0.2(@babel/core@7.28.4):
babel-plugin-transform-hook-names@1.0.2(@babel/core@7.28.5):
dependencies:
'@babel/core': 7.28.4
'@babel/core': 7.28.5
balanced-match@1.0.2: {}
base64-js@1.5.1: {}
baseline-browser-mapping@2.8.19: {}
baseline-browser-mapping@2.8.20: {}
bin-build@3.0.0:
dependencies:
@@ -3993,7 +3993,7 @@ snapshots:
browserslist@4.27.0:
dependencies:
baseline-browser-mapping: 2.8.19
baseline-browser-mapping: 2.8.20
caniuse-lite: 1.0.30001751
electron-to-chromium: 1.5.239
node-releases: 2.0.26
@@ -5935,7 +5935,7 @@ snapshots:
spdx-correct: 3.2.0
spdx-expression-parse: 3.0.1
vite-plugin-imagemin@0.6.1(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0)):
vite-plugin-imagemin@0.6.1(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0)):
dependencies:
'@types/imagemin': 7.0.1
'@types/imagemin-gifsicle': 7.0.4
@@ -5960,11 +5960,11 @@ snapshots:
imagemin-webp: 6.1.0
jpegtran-bin: 6.0.1
pathe: 0.2.0
vite: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
vite: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
vite-prerender-plugin@0.5.12(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0)):
vite-prerender-plugin@0.5.12(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0)):
dependencies:
kolorist: 1.8.0
magic-string: 0.30.19
@@ -5972,20 +5972,20 @@ snapshots:
simple-code-frame: 1.3.0
source-map: 0.7.6
stack-trace: 1.0.0-pre2
vite: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
vite: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.11(@types/node@24.9.1)(terser@5.44.0)):
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@24.9.1)(terser@5.44.0)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.3)
optionalDependencies:
vite: 7.1.11(@types/node@24.9.1)(terser@5.44.0)
vite: 7.1.12(@types/node@24.9.1)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
- typescript
vite@7.1.11(@types/node@24.9.1)(terser@5.44.0):
vite@7.1.12(@types/node@24.9.1)(terser@5.44.0):
dependencies:
esbuild: 0.25.11
fdir: 6.5.0(picomatch@4.0.3)

View File

@@ -30,8 +30,8 @@ packages:
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.28.3':
resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-globals@7.28.0':
@@ -42,12 +42,12 @@ packages:
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.27.1':
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.28.4':
resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==}
'@babel/parser@7.28.5':
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -55,12 +55,12 @@ packages:
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.28.4':
resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==}
'@babel/traverse@7.28.5':
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.28.4':
resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==}
'@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
'@jridgewell/gen-mapping@0.3.13':
@@ -160,14 +160,14 @@ snapshots:
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/generator@7.28.3':
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.4
'@babel/types': 7.28.4
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
@@ -176,34 +176,34 @@ snapshots:
'@babel/helper-string-parser@7.27.1': {}
'@babel/helper-validator-identifier@7.27.1': {}
'@babel/helper-validator-identifier@7.28.5': {}
'@babel/parser@7.28.4':
'@babel/parser@7.28.5':
dependencies:
'@babel/types': 7.28.4
'@babel/types': 7.28.5
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.4
'@babel/types': 7.28.4
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@babel/traverse@7.28.4':
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.3
'@babel/generator': 7.28.5
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.4
'@babel/types': 7.28.5
debug: 4.4.3
transitivePeerDependencies:
- supports-color
'@babel/types@7.28.4':
'@babel/types@7.28.5':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -229,10 +229,10 @@ snapshots:
'@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.6.2)':
dependencies:
'@babel/generator': 7.28.3
'@babel/parser': 7.28.4
'@babel/traverse': 7.28.4
'@babel/types': 7.28.4
'@babel/generator': 7.28.5
'@babel/parser': 7.28.5
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
javascript-natural-sort: 0.7.1
lodash: 4.17.21
prettier: 3.6.2

View File

@@ -30,7 +30,7 @@ default_envs = debug
; uncomment if you want to upload the firmware via OTA (must have upload_protocol = custom)
extra_scripts =
pre:scripts/build_interface.py ; builds the WebUI (unless NO_BUILD_WEBUI is set) - comment out if you don't want to build each time
pre:scripts/build_interface.py ; builds the WebUI - comment out if you don't want to build each time
scripts/rename_fw.py ; renames the firmware .bin file - comment out if not needed
scripts/upload.py ; optionally upload the firmware via OTA (must have upload_protocol = custom)

View File

@@ -98,9 +98,9 @@ build_flags =
build_unflags =
${common.unbuild_flags}
extra_scripts =
pre:scripts/build_interface.py ; builds the WebUI (unless NO_BUILD_WEBUI is set)
; pre:scripts/build_interface.py ; builds the WebUI
scripts/rename_fw.py ; renames the firmware .bin file
scripts/upload.py ; optionally upload the firmware via OTA (if upload_protocol = custom)
; scripts/upload.py ; optionally upload the firmware via OTA (if upload_protocol = custom)
monitor_speed = 115200
monitor_filters = direct
build_type = release
@@ -111,11 +111,16 @@ lib_deps =
ESP32Async/ESPAsyncWebServer @ 3.8.1
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
; builds the web interface only, not the firmware
[env:build_webUI]
platform = native
targets = build
extra_scripts = post:scripts/build_interface.py
;
; Builds for different board types
; We use Tasmota for boards without PSRAM as this framework has mbedtls removed to save memory.
;
; Note, if the system environment variable (windows or linux) "NO_BUILD_WEBUI" is set, the WebUI will not be built.
; If you're building for a single target environment, we recommend creating a pio_local.ini (see example file)
;
@@ -175,6 +180,7 @@ board = seeed_xiao_esp32c6
build_flags =
${common.build_flags}
-DBOARD_C6
;
; Building and testing natively, standalone without an ESP32.
; See https://docs.platformio.org/en/latest/platforms/native.html
@@ -193,15 +199,12 @@ build_flags =
;
[env:native]
platform = native
extra_scripts =
build_flags =
build_type = debug
build_src_flags =
-DARDUINOJSON_ENABLE_ARDUINO_STRING=1
-DEMSESP_STANDALONE -DEMSESP_TEST
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.7.3-dev.0\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
-std=gnu++17 -Og -ggdb
build_unflags = -std=gnu++11 -std=gnu++14
build_type = debug
build_src_flags =
-Wall -Wextra
-Wno-unused-parameter -Wno-sign-compare -Wno-missing-braces
-I./src/core
@@ -232,7 +235,6 @@ lib_deps =
; then re-run and capture the output between "START - CUT HERE" and "END - CUT HERE" into the test_api.h file
[env:native-test]
platform = native
extra_scripts =
test_build_src = true
build_flags =
; -DEMSESP_UNITY_CREATE
@@ -271,3 +273,30 @@ lib_ldf_mode = off
lib_deps = Unity
test_testing_command =
${platformio.build_dir}/${this.__env__}/program
# builds the modbus_entity_parameters.hpp header file
# pio run -e build_modbus -t build
[env:build_modbus]
extends = env:native
targets = build
extra_scripts =
pre:scripts/build_modbus_entity_parameters_pre.py
post:scripts/build_run_test.py
build_flags = -DEMSESP_MODBUS
custom_test_command = entity_dump
custom_output_file = dump_entities.csv
custom_post_script = scripts/build_modbus_entity_parameters_post.py
; builds the real dump_entities.csv and dump_telegrams.csv files
; and the Modbus-Entity-Registers.md file
; to be run after build_modbus with: pio run -e build_standalone -t clean -t build
[env:build_standalone]
extends = env:native
targets = build
extra_scripts =
post:scripts/build_run_test.py
build_flags = -DEMSESP_STANDALONE
custom_test_command = entity_dump
custom_output_file = dump_entities.csv
custom_post_script = scripts/build_modbus_generate_doc_post.py

View File

@@ -1,29 +1,120 @@
from pathlib import Path
import os
import subprocess
import shutil
Import("env")
def buildWeb():
os.chdir("interface")
print("Building web interface...")
def get_pnpm_executable():
"""Get the appropriate pnpm executable for the current platform."""
# Try different pnpm executable names
pnpm_names = ['pnpm', 'pnpm.cmd', 'pnpm.exe']
for name in pnpm_names:
if shutil.which(name):
return name
# Fallback to pnpm if not found
return 'pnpm'
def run_command_in_directory(command, directory):
"""Run a command in a specific directory."""
try:
env.Execute("pnpm install")
env.Execute("pnpm typesafe-i18n")
with open("./src/i18n/i18n-util.ts") as r:
text = r.read().replace("Locales = 'pl'", "Locales = 'en'")
with open("./src/i18n/i18n-util.ts", "w") as w:
w.write(text)
print("Setting WebUI locale to 'en'")
env.Execute("pnpm build")
env.Execute("pnpm webUI")
finally:
os.chdir("..")
result = subprocess.run(
command,
shell=True,
cwd=directory,
check=True,
capture_output=True,
text=True
)
if result.stdout:
print(result.stdout)
if result.stderr:
print(result.stderr)
return True
except subprocess.CalledProcessError as e:
print(f"Command failed: {command}")
print(f"Error: {e}")
if e.stdout:
print(f"Output: {e.stdout}")
if e.stderr:
print(f"Error output: {e.stderr}")
return False
except Exception as e:
print(f"Unexpected error running command '{command}': {e}")
return False
# Don't buuld webUI if called from GitHub Actions
if "NO_BUILD_WEBUI" in os.environ:
print("!! Skipping the build of the web interface !!")
else:
if not (env.IsCleanTarget()):
buildWeb()
def buildWeb():
interface_dir = Path("interface")
pnpm_exe = get_pnpm_executable()
# Set CI environment variable to make pnpm use silent mode
os.environ['CI'] = 'true'
print("Building web interface...")
# Check if interface directory exists
if not interface_dir.exists():
print(f"Error: Interface directory '{interface_dir}' not found!")
return False
# Check if pnpm is available
if not shutil.which(pnpm_exe):
print(f"Error: '{pnpm_exe}' not found in PATH!")
return False
try:
# Run pnpm commands in the interface directory
commands = [
f"{pnpm_exe} install",
f"{pnpm_exe} typesafe-i18n",
f"{pnpm_exe} build",
f"{pnpm_exe} webUI"
]
for command in commands:
print(f"Running: {command}")
if not run_command_in_directory(command, interface_dir):
return False
# Modify i18n-util.ts file
i18n_file = interface_dir / "src" / "i18n" / "i18n-util.ts"
if i18n_file.exists():
with open(i18n_file, 'r') as r:
text = r.read().replace("Locales = 'pl'", "Locales = 'en'")
with open(i18n_file, 'w') as w:
w.write(text)
print("Setting WebUI locale to 'en'")
else:
print(f"Warning: {i18n_file} not found, skipping locale modification")
print("Web interface build completed successfully!")
return True
except Exception as e:
print(f"Error building web interface: {e}")
return False
def build_webUI(*args, **kwargs):
success = buildWeb()
if not success:
print("Web interface build failed!")
env.Exit(1)
env.Exit(0)
# Create custom target that only runs the script
env.AddCustomTarget(
name="build",
dependencies=None,
actions=[build_webUI],
title="build web interface",
description="installs pnpm packages, updates libraries and builds web UI"
)

View File

@@ -0,0 +1,52 @@
import subprocess
import os
import sys
import shutil
from pathlib import Path
def get_python_executable():
"""Get the appropriate Python executable for the current platform."""
# Try different Python executable names
python_names = ['python3', 'python', 'py']
for name in python_names:
if shutil.which(name):
return name
# Fallback to sys.executable if available
return sys.executable
def csv_to_header(csv_file_path, header_file_path, script_path):
# Ensure the output directory exists
Path(header_file_path).parent.mkdir(parents=True, exist_ok=True)
# delete the output file if it exists
if os.path.exists(header_file_path):
os.remove(header_file_path)
# Read CSV file and pipe to Python script to generate header
python_exe = get_python_executable()
with open(csv_file_path, 'r') as csv_file:
with open(header_file_path, 'w') as header_file:
subprocess.run(
[python_exe, script_path],
stdin=csv_file,
stdout=header_file,
check=True
)
print(f"Generated header file: {header_file_path} ({os.path.getsize(header_file_path)} bytes)")
def main():
csv_file = os.path.join("docs", "dump_entities.csv")
header_file = os.path.join("src", "core", "modbus_entity_parameters.hpp")
script_file = os.path.join("scripts", "update_modbus_registers.py")
csv_to_header(csv_file, header_file, script_file)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,40 @@
from pathlib import Path
import os
Import("env")
def create_dummy_modbus_header():
"""Create a dummy modbus_entity_parameters.hpp so the first pass compiles."""
header_content = '''#include "modbus.h"
#include "emsdevice.h"
/*
* This file is auto-generated. Do not modify.
*/
// clang-format off
namespace emsesp {
using dt = EMSdevice::DeviceType;
#define REGISTER_MAPPING(device_type, device_value_tag_type, long_name, modbus_register_offset, modbus_register_count) \\
{ device_type, device_value_tag_type, long_name[0], modbus_register_offset, modbus_register_count }
// IMPORTANT: This list MUST be ordered by keys "device_type", "device_value_tag_type" and "modbus_register_offset" in this order.
const std::initializer_list<Modbus::EntityModbusInfo> Modbus::modbus_register_mappings = {};
} // namespace emsesp
// clang-format on
'''
header_path = Path("src") / "core" / "modbus_entity_parameters.hpp"
header_path.parent.mkdir(parents=True, exist_ok=True)
with open(header_path, 'w') as f:
f.write(header_content)
print(f"Created dummy header file: {header_path} ({os.path.getsize(header_path)} bytes)")
if not (env.IsCleanTarget()):
create_dummy_modbus_header()

View File

@@ -0,0 +1,64 @@
import subprocess
import os
import sys
import shutil
from pathlib import Path
# Import the streaming function from the separate module
from run_executable import run_with_streaming_input
def get_python_executable():
"""Get the appropriate Python executable for the current platform."""
# Try different Python executable names
python_names = ['python3', 'python', 'py']
for name in python_names:
if shutil.which(name):
return name
# Fallback to sys.executable if available
return sys.executable
def csv_to_md(csv_file_path, output_file_path, script_path):
# Ensure the output directory exists
Path(output_file_path).parent.mkdir(parents=True, exist_ok=True)
# delete the output file if it exists
if os.path.exists(output_file_path):
os.remove(output_file_path)
# Read CSV file and pipe to Python script to generate header
python_exe = get_python_executable()
with open(csv_file_path, 'r') as csv_file:
with open(output_file_path, 'w') as output_file:
subprocess.run(
[python_exe, script_path],
stdin=csv_file,
stdout=output_file,
check=True
)
print(f"Generated MD file: {output_file_path} ({os.path.getsize(output_file_path)} bytes)")
def main(program_path="./emsesp"):
csv_file = os.path.join("docs", "dump_entities.csv")
output_file = os.path.join("docs", "Modbus-Entity-Registers.md")
script_file = os.path.join("scripts", "generate-modbus-register-doc.py")
# generate the MD file
csv_to_md(csv_file, output_file, script_file)
# run the test command and generate the dump_telegrams.csv file
test_command = "test telegram_dump"
telegram_output_file = os.path.join("docs", "dump_telegrams.csv")
print(f"Running test command: telegram_dump > {telegram_output_file}")
run_with_streaming_input(program_path, test_command, telegram_output_file)
if __name__ == "__main__":
# Get program path from command line argument or use default
program_path = sys.argv[1] if len(sys.argv) > 1 else "./emsesp"
main(program_path)

46
scripts/build_run_test.py Executable file
View File

@@ -0,0 +1,46 @@
import os
import shutil
import subprocess
import sys
Import("env")
# Import the streaming function from the separate module
from run_executable import run_with_streaming_input
def get_python_executable():
"""Get the appropriate Python executable for the current platform."""
# Try different Python executable names
python_names = ['python3', 'python', 'py']
for name in python_names:
if shutil.which(name):
return name
# Fallback to sys.executable if available
return sys.executable
def build_run_test(source, target, env):
# Get the executable path
program_path = source[0].get_abspath()
# Get output file and test command from environment variable or use defaults
output_file = os.path.join("docs", env.GetProjectOption("custom_output_file", "dump_default_output.txt"))
test_command = env.GetProjectOption("custom_test_command", "test entity_dump")
# run the test command and save the output to the output file
run_with_streaming_input(program_path, test_command, output_file)
# if we have a post command defined run it
post_script = env.GetProjectOption("custom_post_script", None)
if post_script:
print(f"Running post script: {post_script}")
python_exe = get_python_executable()
subprocess.run([python_exe, post_script, program_path], check=True)
env.AddCustomTarget(
"build",
"$BUILD_DIR/${PROGNAME}$PROGSUFFIX",
build_run_test
)

14
scripts/force_clean.py Normal file
View File

@@ -0,0 +1,14 @@
Import("env")
import os
import shutil
def force_clean(source, target, env):
"""Remove build directory before building"""
build_dir = env.subst("$BUILD_DIR")
if os.path.exists(build_dir):
print(f"Force cleaning: {build_dir}")
shutil.rmtree(build_dir)
# Register the callback to run before building
env.AddPreAction("$BUILD_DIR/${PROGNAME}$PROGSUFFIX", force_clean)

135
scripts/run_executable.py Executable file
View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""
Utility functions for running executables with streaming input and CSV output extraction.
"""
import subprocess
import sys
import os
from pathlib import Path
def run_with_streaming_input(program_path, test_command, output_file=None):
"""
Run the executable and stream text input to it.
Args:
program_path (str): Path to the executable to run
test_command (str): Command to send to the executable
output_file (str, optional): Path to save CSV output. If None, no file is saved.
Returns:
int: Return code of the executed process
"""
try:
# Start the process with pipes for stdin, stdout, and stderr
process = subprocess.Popen(
[str(program_path)],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=1 # Line buffered
)
# add "test " to test_command if it doesn't already start with "test "
if not test_command.startswith("test "):
test_command = "test " + test_command
# Stream input line by line
for line in test_command.strip().split('\n'):
process.stdin.write(line + '\n')
process.stdin.flush()
# Close stdin to signal end of input
process.stdin.close()
# Read and collect output between CSV START and CSV END, then export to file
in_cvs_section = False
csv_output = []
for line in process.stdout:
if "---- CSV START ----" in line:
in_cvs_section = True
continue
elif "---- CSV END ----" in line:
in_cvs_section = False
continue
elif in_cvs_section:
csv_output.append(line)
# print(line, end='')
# Export CSV output to file if output_file is specified
if output_file:
# Ensure the output directory exists
Path(output_file).parent.mkdir(parents=True, exist_ok=True)
# delete the output file if it exists
if os.path.exists(output_file):
os.remove(output_file)
# Export CSV output to file
with open(output_file, 'w') as f:
f.writelines(csv_output)
print(f"CSV file created: {output_file} ({os.path.getsize(output_file)} bytes)")
# Wait for process to complete
return_code = process.wait()
# Print any errors
stderr_output = process.stderr.read()
if stderr_output:
print("\nErrors:", file=sys.stderr)
print(stderr_output, file=sys.stderr)
return return_code
except Exception as e:
print(f"Error running executable: {e}", file=sys.stderr)
return 1
def run_executable_with_command(program_path, command, output_file=None):
"""
Simplified interface to run an executable with a command and optionally save output.
Args:
program_path (str): Path to the executable to run
command (str): Command to send to the executable
output_file (str, optional): Path to save CSV output. If None, no file is saved.
Returns:
int: Return code of the executed process
"""
return run_with_streaming_input(program_path, command, output_file)
def main():
"""Command-line interface for running executables with streaming input."""
if len(sys.argv) < 3:
print("Usage: python3 run_executable.py <program_path> <command> [output_file]")
print("Example: python3 run_executable.py ./emsesp entity_dump ./output.csv")
sys.exit(1)
program_path = sys.argv[1]
command = sys.argv[2]
output_file = sys.argv[3] if len(sys.argv) > 3 else None
print(f"Running: {program_path}")
print(f"Command: {command}")
if output_file:
print(f"Output file: {output_file}")
return_code = run_with_streaming_input(program_path, command, output_file)
if return_code == 0:
print("Execution completed successfully!")
else:
print(f"Execution failed with return code: {return_code}")
sys.exit(return_code)
if __name__ == "__main__":
main()

View File

@@ -26,4 +26,3 @@ pnpm webUI
cd ..
npx cspell "**"
sh ./scripts/generate_csv_and_headers.sh

View File

@@ -228,10 +228,12 @@ void RxService::add(uint8_t * data, uint8_t length) {
// create the telegram
auto telegram = std::make_shared<Telegram>(operation, src, dest, type_id, offset, message_data, message_length);
// check if queue is full, if so remove top item to make space
// check if queue is full, if so remove top item to make space, except if we're in standalone mode
#ifndef EMSESP_STANDALONE
if (rx_telegrams_.size() >= MAX_RX_TELEGRAMS) {
rx_telegrams_.pop_front();
}
#endif
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
}
@@ -239,7 +241,7 @@ void RxService::add(uint8_t * data, uint8_t length) {
// add empty telegram to rx-queue
void RxService::add_empty(const uint8_t src, const uint8_t dest, const uint16_t type_id, uint8_t offset) {
auto telegram = std::make_shared<Telegram>(Telegram::Operation::RX, src, dest, type_id, offset, nullptr, 0);
// only if queue is not full
// only if queue is not full
if (rx_telegrams_.size() < MAX_RX_TELEGRAMS) {
rx_telegrams_.emplace_back(rx_telegram_id_++, std::move(telegram)); // add to queue
}
@@ -442,6 +444,7 @@ void TxService::add(const uint8_t operation,
LOG_DEBUG("New Tx [#%d] telegram, length %d", tx_telegram_id_, message_length);
#ifndef EMSESP_STANDALONE
// if the queue is full, make room by removing the last one
if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) {
LOG_WARNING("Tx queue overflow, skip one message");
@@ -452,6 +455,7 @@ void TxService::add(const uint8_t operation,
}
tx_telegrams_.pop_front();
}
#endif
if (front) {
tx_telegrams_.emplace_front(tx_telegram_id_++, std::move(telegram), false, validateid); // add to front of queue

View File

@@ -32,13 +32,8 @@
#include "helpers.h"
#if defined(EMSESP_STANDALONE)
#define MAX_RX_TELEGRAMS 100 // size of Rx queue
#define MAX_TX_TELEGRAMS 200 // size of Tx queue
#else
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
#define MAX_TX_TELEGRAMS 160 // size of Tx queue
#endif
// default values for null values
static constexpr uint8_t EMS_VALUE_BOOL = 0xFF; // used to mark that something is a boolean