Compare commits

...

132 Commits

Author SHA1 Message Date
01f1e123ac fix: increase stack size for sendToApi task to improve stability 2025-04-15 16:38:16 +02:00
012f91851e fix: adjust tare weight tolerance to ignore deviations of 2g 2025-03-31 10:59:54 +02:00
9ed3c70c01 fix: improve weight stability check before sending to API 2025-03-31 10:08:26 +02:00
e23f3a2151 docs: update changelog and header for version v1.5.1
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m52s
2025-03-30 16:38:38 +02:00
f73306f0b9 chore: update version to 1.5.1 and improve OTA update handling with task management 2025-03-30 16:38:23 +02:00
a450d4bd1a docs: update changelog and header for version v1.4.14
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m42s
2025-03-30 16:01:45 +02:00
d48d994c00 docs: update platformio.ini for version v1.4.14 2025-03-30 16:01:45 +02:00
32bb85f897 feat: add auto-tare functionality and update scale handling based on touch sensor connection 2025-03-30 16:01:17 +02:00
e9d32ee060 docs: update changelog and header for version v1.4.13
All checks were successful
Release Workflow / detect-provider (push) Successful in 5s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m44s
2025-03-30 12:59:57 +02:00
aba28422bd docs: update platformio.ini for version v1.4.13 2025-03-30 12:59:57 +02:00
4a55620d39 fix: update touch sensor connection logic to correctly identify connection status 2025-03-30 12:59:51 +02:00
7b18266534 docs: update changelog and header for version v1.4.12
Some checks failed
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Failing after 2m16s
2025-03-30 12:55:33 +02:00
d81acb2b61 docs: update platformio.ini for version v1.4.12 2025-03-30 12:55:33 +02:00
8c7fc159d3 fix: add touch sensor connection check and update logic 2025-03-30 12:55:26 +02:00
476d3e82e2 docs: update README files to clarify PN532 DIP switch settings 2025-03-30 12:35:50 +02:00
3c294a135f docs: update changelog and header for version v1.4.11
All checks were successful
Release Workflow / detect-provider (push) Successful in 2s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m56s
2025-03-30 12:21:57 +02:00
bb751b6289 docs: update platformio.ini for version v1.4.11 2025-03-30 12:21:57 +02:00
7fd01bd1b9 Merge branch 'main' of github.com:ManuelW77/Filaman 2025-03-30 12:21:04 +02:00
fad84e12c8 docs: update changelog and header for version v1.4.10
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m6s
2025-03-30 12:19:25 +02:00
696efc4d79 docs: update platformio.ini for version v1.4.10 2025-03-30 12:19:25 +02:00
29868e7101 fix: update TTP223 pin configuration and adjust touch sensor logic 2025-03-30 12:19:07 +02:00
823db6157c fix: add manual tare functionality for scale 2025-03-29 14:44:33 +01:00
458cc4eaf2
Merge pull request #31 from janecker/nfc_rework
Introducing enum for handling the NFC state to improve code readability
2025-03-29 14:25:20 +01:00
83d14b32d1 fix: add debounce handling for TTP223 touch sensor 2025-03-29 14:23:55 +01:00
2bf7c9fb7d feat: add TTP223 touch sensor support and wiring configuration 2025-03-29 14:18:58 +01:00
Jan Philipp Ecker
ac8adca84d Renamed states of NFC state machine and introduced new state machine for spoolman API 2025-03-29 13:21:47 +01:00
Jan Philipp Ecker
c701149c64 Introducing enum for handling the NFC state to improve code readability 2025-03-29 11:45:38 +01:00
07a919b6ba docs: update changelog and header for version v1.4.9
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m48s
2025-03-29 10:11:25 +01:00
8618b90e33 docs: update platformio.ini for version v1.4.9 2025-03-29 10:11:25 +01:00
57723b5354 fix: enhance HTTP method handling in sendToApi function 2025-03-29 10:03:17 +01:00
d2be752175 docs: update changelog and header for version v1.4.8
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m46s
2025-03-29 07:58:12 +01:00
97a050ace8 docs: update platformio.ini for version v1.4.8 2025-03-29 07:58:12 +01:00
367e692c74
Merge pull request #30 from janecker/main
Fix memory leak issue in HTTPClient
2025-03-29 07:55:45 +01:00
926a21249b
Merge branch 'testing' into main 2025-03-29 07:55:33 +01:00
2635c19667 fix: improve HTTP client configuration and clear update documents after API calls 2025-03-29 07:52:49 +01:00
Jan Philipp Ecker
6cc4efca0a Fixes memory leak in HTTPClient by disabling connection reuse 2025-03-28 22:40:50 +01:00
1484a6b0da fix: update reload logic after removing and saving Bambu credentials for better cache handling 2025-03-27 19:13:57 +01:00
b5f0472af4 docs: update changelog and header for version v1.4.7
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m10s
2025-03-27 18:54:33 +01:00
95c1bc823c docs: update platformio.ini for version v1.4.7 2025-03-27 18:54:33 +01:00
491ba7f526 Merge branch 'testing' 2025-03-27 18:54:15 +01:00
56d7d8596c style: update remove button for Bambu credentials with red background 2025-03-27 18:07:33 +01:00
1044e91a0a feat: add forced cache refresh after removing and saving Bambu credentials 2025-03-27 18:03:40 +01:00
e459b53472 feat: add functionality to remove Bambu credentials and update API handling 2025-03-27 18:01:15 +01:00
024056cb7d fix: handle Bambu connection state by introducing bambuDisabled flag 2025-03-27 11:18:04 +01:00
e040a736b0 feat: add rfid_bambu.html and update bambu connection handling 2025-03-27 10:35:10 +01:00
72b6b349c6
Merge pull request #28 from tugsi/main
Fix rfid.js-Failure with X1-Series, if you wanna send a Spool to AMS
2025-03-26 11:54:41 +01:00
190e952ec4 docs: update changelog and header for version v1.4.6
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m57s
2025-03-26 11:52:46 +01:00
89620a7f00 docs: update platformio.ini for version v1.4.6 2025-03-26 11:52:46 +01:00
536950eeb3 fix: handle potential undefined value for tray_info_idx in handleSpoolIn function, by @tugsi 2025-03-26 11:51:58 +01:00
tugsi
fe4d2d7479 Fix rfid.js-Failure with X1-Series,
if you wanna send a Spool to AMS:
 - Uncaught TypeError: Cannot read properties of undefined (reading 'replace')
    at handleSpoolIn (rfid.js:493:67)
    at HTMLButtonElement.onclick ((Index):1:1)
handleSpoolIn	@	rfid.js:493
onclick	@	(Index):1
2025-03-25 17:40:55 +01:00
43719aac41 docs: update changelog and header for version v1.4.5
All checks were successful
Release Workflow / detect-provider (push) Successful in 4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m21s
2025-03-25 12:11:56 +01:00
16d0079f7a docs: update platformio.ini for version v1.4.5 2025-03-25 12:11:56 +01:00
48b9bf7076 Merge branch 'testing' 2025-03-25 12:08:08 +01:00
b6bd4cb9ad refactor: remove unused request_topic subscription and reduce MQTT task stack size 2025-03-25 12:05:34 +01:00
e89bb1d547 fix: increase MQTT buffer size and adjust task stack size 2025-03-25 12:02:54 +01:00
f25789d703
Merge pull request #26 from tugsi/main
Fix BufferSize for larger JSONs from X-Series
2025-03-25 12:01:57 +01:00
tugsi
65d8cd675f Fix BufferSize for larger JSONs from X-Series 2025-03-24 12:17:28 +01:00
9dfe75ffa2 refactor: rename report_topic to topic and update MQTT subscription logic, switched publish topic to request 2025-03-23 18:01:53 +01:00
68cdd8ab40 docs: update changelog and header for version v1.4.4
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m10s
2025-03-23 16:50:29 +01:00
1069781931 docs: update platformio.ini for version v1.4.4 2025-03-23 16:50:29 +01:00
eada54eff2 fix: add error handling for missing vendor IDs in filament data 2025-03-23 16:28:13 +01:00
48301ade36 fix: adjust weight threshold for tare check to allow negative values 2025-03-23 15:03:37 +01:00
76e0b20393 docs: update changelog and header for version v1.4.3
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m48s
2025-03-23 11:38:57 +01:00
a765b39896 docs: update platformio.ini for version v1.4.3 2025-03-23 11:38:57 +01:00
d68f6c4a89 docs: update changelog and header for version v1.4.2
All checks were successful
Release Workflow / detect-provider (push) Successful in 1m4s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 3m14s
2025-03-23 11:25:52 +01:00
1702e2396e docs: update platformio.ini for version v1.4.2 2025-03-23 11:25:52 +01:00
af23b07df1 fix: use unique client ID for MQTT connection to avoid conflicts 2025-03-23 11:24:46 +01:00
dd7ba3bf5d fix: reload page after firmware update completion 2025-03-23 11:15:38 +01:00
a818dcd3c0 fix: increase WiFi connection timeout from 5 to 10 seconds 2025-03-23 11:05:10 +01:00
b5279b167a fix: ensure valid URL format and remove trailing slash in setupWebserver 2025-03-23 11:03:57 +01:00
a09fd4fda4 fix: add WiFi connection check and restart Bambu if not connected 2025-03-23 11:03:51 +01:00
e4fe08f54c increase stack size for BambuMqtt task 2025-03-23 10:41:28 +01:00
3eac0e5ac4 update Discord Link 2025-03-15 16:02:18 +01:00
24d91693d9 update Discord Link 2025-03-15 15:57:46 +01:00
94c26590c8 remove commented-out subscription topic in MQTT setup 2025-03-10 17:41:14 +01:00
4559bae066 docs: update changelog and header for version v1.4.1
All checks were successful
Release Workflow / detect-provider (push) Successful in 1m22s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m48s
2025-03-10 17:34:09 +01:00
cdb2d16cf9 docs: update platformio.ini for version v1.4.1 2025-03-10 17:34:09 +01:00
cd71949c82 refactor length calculation to convert total length to meters before formatting 2025-03-10 17:33:47 +01:00
6cd280389d
Merge pull request #16 from spitzbirne32/main
Usermod for M3 heat inserts and AliExpress parts
2025-03-06 15:19:28 +01:00
spitzbirne32
daf27820b1
improved housing to show display better 2025-03-06 12:16:10 +01:00
spitzbirne32
dd7fbe1119
added new .step, now with correct individual parts 2025-03-06 12:14:39 +01:00
spitzbirne32
dc2ddb47eb
removed CAD, as they were all duplicates 2025-03-06 12:13:25 +01:00
spitzbirne32
6bb8f565e6
typo in AliE link 2025-03-04 01:59:47 +01:00
spitzbirne32
ec60ca88f1
added changelog 2025-03-04 01:57:50 +01:00
spitzbirne32
17664acf9e
Delete usermod/spitzbirne32/STL/README.md 2025-03-04 01:48:02 +01:00
spitzbirne32
18f7454a76
Add files via upload 2025-03-04 01:43:50 +01:00
spitzbirne32
e7b5917888
added .stp files of modifications 2025-03-04 01:43:20 +01:00
spitzbirne32
5c57968ba9
Update README.md 2025-03-04 01:40:33 +01:00
spitzbirne32
795c926c1f
added merged picture 2025-03-04 01:33:01 +01:00
spitzbirne32
8735a9740c
moved pictures of parts into dedicated folders 2025-03-04 01:26:41 +01:00
spitzbirne32
02d0adc6bf
added pictures of components bought from AliE 2025-03-04 01:21:18 +01:00
spitzbirne32
24067666ed
Update README.md 2025-03-04 01:17:12 +01:00
spitzbirne32
9264333eda
Add files via upload 2025-03-04 01:06:07 +01:00
spitzbirne32
66216d57ae
Update README.md 2025-03-04 01:05:35 +01:00
spitzbirne32
5100a669b0
Update README.md 2025-03-04 00:54:43 +01:00
spitzbirne32
4ad89b68a7
added pictures for heat insert location 2025-03-04 00:50:42 +01:00
spitzbirne32
758acaff9f
Delete usermod/spitzbirne32/STL/ScaleTop_Heatinsert_Location_usermod_spitzbirne32_.png 2025-03-04 00:50:22 +01:00
spitzbirne32
fed96b9c58
Delete usermod/spitzbirne32/STL/Housing_Heatinsert_Location_usermod_spitzbirne32_.png 2025-03-04 00:50:14 +01:00
spitzbirne32
2d072ee09a
added pictures showing heat insert location 2025-03-04 00:49:31 +01:00
spitzbirne32
b55b6e3fd5
created folders 2025-03-04 00:26:37 +01:00
spitzbirne32
238b928236
Update README.md 2025-03-04 00:16:01 +01:00
spitzbirne32
24ce0ca6df
Update README.md 2025-03-04 00:15:10 +01:00
spitzbirne32
3cf934b920
Create README.md 2025-03-04 00:11:54 +01:00
spitzbirne32
f68ea3edb0
Update README.md 2025-03-04 00:09:49 +01:00
spitzbirne32
16321c9461
Update README.md 2025-03-04 00:05:21 +01:00
spitzbirne32
f9530f6d9a
Create README.md 2025-03-03 22:08:45 +01:00
83f2f0834d
Merge pull request #15 from ManuelW77/main
set to main state
2025-03-03 17:10:35 +01:00
6632aa8f95
Merge pull request #14 from janecker/scale-calibration-rework
Reworks the scale calibration handling
2025-03-03 17:08:06 +01:00
8a558c3121 refactor: remove unnecessary delay in MQTT setup and add delay before restart 2025-03-03 16:58:24 +01:00
Jan Philipp Ecker
d434fde92e Reworks the scale calibration handling
Fixes some issues in the scale handling. Prevents a wdg reset after
after scale calibration. Also makes sure that after calibration all
tasks are started again that have been suspsended before.
2025-03-03 16:50:46 +01:00
5afb60df32 fix: correct typo in console log for total length 2025-03-02 20:21:27 +01:00
3394e6eb01 feat: add new 3D print file for Filaman scale 2025-03-02 08:06:59 +01:00
3818c2c059 refactor: remove redundant scale calibration checks and enhance task management 2025-03-01 18:50:20 +01:00
0afc543b5f refactor: enhance AMS data handling and streamline spool auto-setting logic 2025-03-01 18:44:35 +01:00
adee46e3fc refactor: adjust stack size and improve scale calibration logic 2025-03-01 18:44:29 +01:00
1db74867e6 refactor: update labels and input types for better clarity and functionality 2025-03-01 18:44:17 +01:00
0f24a63d32 added Discord Server 2025-03-01 15:33:39 +01:00
3640809502 update documentation for clarity and accuracy 2025-03-01 13:04:28 +01:00
289d5357be docs: update changelog and header for version v1.4.0
All checks were successful
Release Workflow / detect-provider (push) Successful in 5s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m45s
2025-03-01 12:46:18 +01:00
315530d1ea update NFC tag references to include NTAG213 and clarify storage capacity 2025-03-01 12:45:55 +01:00
f36773a4c4 bump version to 1.4.0 2025-03-01 12:37:50 +01:00
b35163936f add support for Spoolman Octoprint Plugin in README files 2025-03-01 12:33:26 +01:00
7a2c9d6d17 add OctoPrint integration with configurable fields and update functionality 2025-03-01 12:18:33 +01:00
eb2a8dc128 add version comparison function and check for outdated versions before updates 2025-03-01 12:18:21 +01:00
bec2c91331 remove unused version and protocol fields from JSON output; add error message for insufficient memory 2025-03-01 10:42:06 +01:00
c6e727de06 remove unused version and protocol fields from NFC data packet 2025-03-01 10:41:51 +01:00
3253e7d407 sort vendors alphabetically in the dropdown list 2025-03-01 10:41:44 +01:00
bce2ad2ed8
Merge pull request #10 from janecker/nfc-improvements
Improves NFC Tag handling
2025-03-01 10:03:46 +01:00
Jan Philipp Ecker
0eff29ef4a Improves NFC Tag handling
Fixes memory underflow when reading tags. Reads tags with their actual data size and uses actual size instead of constnat value for tag size when writing a tag.
2025-02-28 22:35:34 +01:00
492bf6cdb8 docs: update changelog and header for version v1.3.99
All checks were successful
Release Workflow / detect-provider (push) Successful in 3s
Release Workflow / github-release (push) Has been skipped
Release Workflow / gitea-release (push) Successful in 2m39s
2025-02-28 18:35:16 +01:00
b0317f4001 docs: update platformio.ini for version v1.3.99 2025-02-28 18:35:16 +01:00
58ff6458b0 refactor: update workflows to build firmware with LittleFS instead of SPIFFS 2025-02-28 18:35:05 +01:00
52 changed files with 49433 additions and 284 deletions

View File

@ -41,16 +41,16 @@ jobs:
run: | run: |
VERSION=$(grep '^version = ' platformio.ini | cut -d'"' -f2) VERSION=$(grep '^version = ' platformio.ini | cut -d'"' -f2)
# Build firmware and SPIFFS # Build firmware and LittleFS
echo "Building firmware and SPIFFS..." echo "Building firmware and LittleFS..."
pio run -e esp32dev pio run -e esp32dev
pio run -t buildfs pio run -t buildfs
# Copy firmware binary # Copy firmware binary
cp .pio/build/esp32dev/firmware.bin .pio/build/esp32dev/upgrade_filaman_firmware_v${VERSION}.bin cp .pio/build/esp32dev/firmware.bin .pio/build/esp32dev/upgrade_filaman_firmware_v${VERSION}.bin
# Create SPIFFS binary - direct copy without header # Create LittleFS binary - direct copy without header
cp .pio/build/esp32dev/spiffs.bin .pio/build/esp32dev/upgrade_filaman_website_v${VERSION}.bin cp .pio/build/esp32dev/littlefs.bin .pio/build/esp32dev/upgrade_filaman_website_v${VERSION}.bin
# Create full binary # Create full binary
(cd .pio/build/esp32dev && (cd .pio/build/esp32dev &&
@ -63,7 +63,7 @@ jobs:
0x1000 bootloader.bin \ 0x1000 bootloader.bin \
0x8000 partitions.bin \ 0x8000 partitions.bin \
0x10000 firmware.bin \ 0x10000 firmware.bin \
0x3D0000 spiffs.bin) 0x3D0000 littlefs.bin)
# Verify file sizes # Verify file sizes
echo "File sizes:" echo "File sizes:"

View File

@ -39,16 +39,16 @@ jobs:
run: | run: |
VERSION=$(grep '^version = ' platformio.ini | cut -d'"' -f2) VERSION=$(grep '^version = ' platformio.ini | cut -d'"' -f2)
# Always build firmware and SPIFFS # Always build firmware and LittleFS
echo "Building firmware and SPIFFS..." echo "Building firmware and LittleFS..."
pio run -e esp32dev pio run -e esp32dev
pio run -t buildfs pio run -t buildfs
# Copy firmware binary # Copy firmware binary
cp .pio/build/esp32dev/firmware.bin .pio/build/esp32dev/upgrade_filaman_firmware_v${VERSION}.bin cp .pio/build/esp32dev/firmware.bin .pio/build/esp32dev/upgrade_filaman_firmware_v${VERSION}.bin
# Create SPIFFS binary - direct copy without header # Create LittleFS binary - direct copy without header
cp .pio/build/esp32dev/spiffs.bin .pio/build/esp32dev/upgrade_filaman_website_v${VERSION}.bin cp .pio/build/esp32dev/littlefs.bin .pio/build/esp32dev/upgrade_filaman_website_v${VERSION}.bin
# Create full binary (always) # Create full binary (always)
(cd .pio/build/esp32dev && (cd .pio/build/esp32dev &&
@ -61,7 +61,7 @@ jobs:
0x1000 bootloader.bin \ 0x1000 bootloader.bin \
0x8000 partitions.bin \ 0x8000 partitions.bin \
0x10000 firmware.bin \ 0x10000 firmware.bin \
0x3D0000 spiffs.bin) 0x3D0000 littlefs.bin)
# Verify file sizes # Verify file sizes
echo "File sizes:" echo "File sizes:"
@ -131,7 +131,7 @@ jobs:
FILES_TO_UPLOAD="$FILES_TO_UPLOAD upgrade_filaman_firmware_v${VERSION}.bin" FILES_TO_UPLOAD="$FILES_TO_UPLOAD upgrade_filaman_firmware_v${VERSION}.bin"
fi fi
# Add SPIFFS and full binary only if they exist # Add LittleFS and full binary only if they exist
if [ -f "upgrade_filaman_website_v${VERSION}.bin" ]; then if [ -f "upgrade_filaman_website_v${VERSION}.bin" ]; then
FILES_TO_UPLOAD="$FILES_TO_UPLOAD upgrade_filaman_website_v${VERSION}.bin" FILES_TO_UPLOAD="$FILES_TO_UPLOAD upgrade_filaman_website_v${VERSION}.bin"
fi fi

View File

@ -1,5 +1,223 @@
# Changelog # Changelog
## [1.5.1] - 2025-03-30
### Changed
- update version to 1.5.1 and improve OTA update handling with task management
## [1.4.14] - 2025-03-30
### Added
- add auto-tare functionality and update scale handling based on touch sensor connection
### Changed
- update platformio.ini for version v1.4.14
## [1.4.13] - 2025-03-30
### Changed
- update platformio.ini for version v1.4.13
### Fixed
- update touch sensor connection logic to correctly identify connection status
## [1.4.12] - 2025-03-30
### Added
- add touch sensor connection check and update logic
### Changed
- update platformio.ini for version v1.4.12
- update README files to clarify PN532 DIP switch settings
## [1.4.11] - 2025-03-30
### Added
- Renamed states of NFC state machine and introduced new state machine for spoolman API
### Changed
- update platformio.ini for version v1.4.11
- Merge branch 'main' of github.com:ManuelW77/Filaman
- Merge pull request #31 from janecker/nfc_rework
- Introducing enum for handling the NFC state to improve code readability
## [1.4.10] - 2025-03-30
### Added
- add manual tare functionality for scale
- add debounce handling for TTP223 touch sensor
- add TTP223 touch sensor support and wiring configuration
### Changed
- update platformio.ini for version v1.4.10
### Fixed
- update TTP223 pin configuration and adjust touch sensor logic
## [1.4.9] - 2025-03-29
### Changed
- update platformio.ini for version v1.4.9
### Fixed
- enhance HTTP method handling in sendToApi function
## [1.4.8] - 2025-03-29
### Changed
- update platformio.ini for version v1.4.8
- Merge pull request #30 from janecker/main
- Merge branch 'testing' into main
### Fixed
- improve HTTP client configuration and clear update documents after API calls
- Fixes memory leak in HTTPClient by disabling connection reuse
- update reload logic after removing and saving Bambu credentials for better cache handling
## [1.4.7] - 2025-03-27
### Added
- add forced cache refresh after removing and saving Bambu credentials
- add functionality to remove Bambu credentials and update API handling
- add rfid_bambu.html and update bambu connection handling
### Changed
- update platformio.ini for version v1.4.7
- Merge branch 'testing'
- update remove button for Bambu credentials with red background
- Merge pull request #28 from tugsi/main
### Fixed
- handle Bambu connection state by introducing bambuDisabled flag
- Fix rfid.js-Failure with X1-Series, if you wanna send a Spool to AMS: - Uncaught TypeError: Cannot read properties of undefined (reading 'replace') at handleSpoolIn (rfid.js:493:67) at HTMLButtonElement.onclick ((Index):1:1) handleSpoolIn @ rfid.js:493 onclick @ (Index):1
## [1.4.6] - 2025-03-26
### Changed
- update platformio.ini for version v1.4.6
### Fixed
- handle potential undefined value for tray_info_idx in handleSpoolIn function, by @tugsi
## [1.4.5] - 2025-03-25
### Changed
- update platformio.ini for version v1.4.5
- Merge branch 'testing'
- remove unused request_topic subscription and reduce MQTT task stack size
- Merge pull request #26 from tugsi/main
- rename report_topic to topic and update MQTT subscription logic, switched publish topic to request
### Fixed
- increase MQTT buffer size and adjust task stack size
- Fix BufferSize for larger JSONs from X-Series
## [1.4.4] - 2025-03-23
### Added
- add error handling for missing vendor IDs in filament data
### Changed
- update platformio.ini for version v1.4.4
### Fixed
- adjust weight threshold for tare check to allow negative values
## [1.4.3] - 2025-03-23
### Changed
- update platformio.ini for version v1.4.3
## [1.4.2] - 2025-03-23
### Added
- add WiFi connection check and restart Bambu if not connected
### Changed
- update platformio.ini for version v1.4.2
- increase stack size for BambuMqtt task
- update Discord Link
- update Discord Link
- remove commented-out subscription topic in MQTT setup
### Fixed
- use unique client ID for MQTT connection to avoid conflicts
- reload page after firmware update completion
- increase WiFi connection timeout from 5 to 10 seconds
- ensure valid URL format and remove trailing slash in setupWebserver
## [1.4.1] - 2025-03-10
### Added
- added new .step, now with correct individual parts
- added changelog
- Add files via upload
- added .stp files of modifications
- added merged picture
- added pictures of components bought from AliE
- Add files via upload
- added pictures for heat insert location
- added pictures showing heat insert location
- remove unnecessary delay in MQTT setup and add delay before restart
- add new 3D print file for Filaman scale
- added Discord Server
### Changed
- update platformio.ini for version v1.4.1
- refactor length calculation to convert total length to meters before formatting
- Merge pull request #16 from spitzbirne32/main
- improved housing to show display better
- removed CAD, as they were all duplicates
- typo in AliE link
- Delete usermod/spitzbirne32/STL/README.md
- Update README.md
- moved pictures of parts into dedicated folders
- Update README.md
- Update README.md
- Update README.md
- Delete usermod/spitzbirne32/STL/ScaleTop_Heatinsert_Location_usermod_spitzbirne32_.png
- Delete usermod/spitzbirne32/STL/Housing_Heatinsert_Location_usermod_spitzbirne32_.png
- created folders
- Update README.md
- Update README.md
- Create README.md
- Update README.md
- Update README.md
- Create README.md
- Merge pull request #15 from ManuelW77/main
- Merge pull request #14 from janecker/scale-calibration-rework
- Reworks the scale calibration handling
- remove redundant scale calibration checks and enhance task management
- enhance AMS data handling and streamline spool auto-setting logic
- adjust stack size and improve scale calibration logic
- update labels and input types for better clarity and functionality
- update documentation for clarity and accuracy
### Fixed
- correct typo in console log for total length
## [1.4.0] - 2025-03-01
### Added
- add support for Spoolman Octoprint Plugin in README files
- add OctoPrint integration with configurable fields and update functionality
- add version comparison function and check for outdated versions before updates
- remove unused version and protocol fields from JSON output; add error message for insufficient memory
### Changed
- update NFC tag references to include NTAG213 and clarify storage capacity
- bump version to 1.4.0
- remove unused version and protocol fields from NFC data packet
- sort vendors alphabetically in the dropdown list
- Merge pull request #10 from janecker/nfc-improvements
- Improves NFC Tag handling
## [1.3.99] - 2025-02-28
### Changed
- update platformio.ini for version v1.3.99
- update workflows to build firmware with LittleFS instead of SPIFFS
## [1.3.98] - 2025-02-28 ## [1.3.98] - 2025-02-28
### Changed ### Changed
- update platformio.ini for version v1.3.98 - update platformio.ini for version v1.3.98

View File

@ -9,6 +9,7 @@ Das System integriert sich nahtlos mit der [Spoolman](https://github.com/Donkie/
Weitere Bilder finden Sie im [img Ordner](/img/) Weitere Bilder finden Sie im [img Ordner](/img/)
oder auf meiner Website: [FilaMan Website](https://www.filaman.app) oder auf meiner Website: [FilaMan Website](https://www.filaman.app)
Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU) Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU)
Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
### Es gibt jetzt auch ein Wiki, dort sind nochmal alle Funktionen beschrieben: [Wiki](https://github.com/ManuelW77/Filaman/wiki) ### Es gibt jetzt auch ein Wiki, dort sind nochmal alle Funktionen beschrieben: [Wiki](https://github.com/ManuelW77/Filaman/wiki)
@ -18,7 +19,7 @@ Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaO
- **OLED-Display:** Zeigt aktuelles Gewicht, Verbindungsstatus (WiFi, Bambu Lab, Spoolman). - **OLED-Display:** Zeigt aktuelles Gewicht, Verbindungsstatus (WiFi, Bambu Lab, Spoolman).
- **WLAN-Konnektivität:** WiFiManager für einfache Netzwerkkonfiguration. - **WLAN-Konnektivität:** WiFiManager für einfache Netzwerkkonfiguration.
- **MQTT-Integration:** Verbindet sich mit Bambu Lab Drucker für AMS-Steuerung. - **MQTT-Integration:** Verbindet sich mit Bambu Lab Drucker für AMS-Steuerung.
- **NFC-Tag NTAG215:** Verwendung von NTAG215 wegen ausreichendem Speicherplatz auf dem Tag - **NFC-Tag NTAG213 NTAG215:** Verwendung von NTAG213, besser NTAG215 wegen ausreichendem Speicherplatz auf dem Tag
### Weboberflächen-Funktionen ### Weboberflächen-Funktionen
- **Echtzeit-Updates:** WebSocket-Verbindung für Live-Daten-Updates. - **Echtzeit-Updates:** WebSocket-Verbindung für Live-Daten-Updates.
@ -35,6 +36,7 @@ Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaO
- Filtern und Auswählen von Filamenten. - Filtern und Auswählen von Filamenten.
- Automatische Aktualisierung der Spulengewichte. - Automatische Aktualisierung der Spulengewichte.
- Verfolgung von NFC-Tag-Zuweisungen. - Verfolgung von NFC-Tag-Zuweisungen.
- Unterstützt das Spoolman Octoprint Plugin
### Wenn Sie meine Arbeit unterstützen möchten, freue ich mich über einen Kaffee ### Wenn Sie meine Arbeit unterstützen möchten, freue ich mich über einen Kaffee
<a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a> <a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a>
@ -53,19 +55,22 @@ Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaO
## Hardware-Anforderungen ## Hardware-Anforderungen
### Komponenten ### Komponenten
- **ESP32 Entwicklungsboard:** Jede ESP32-Variante. - **ESP32 Development Board:** Any ESP32 variant.
[Amazon Link](https://amzn.eu/d/aXThslf) [Amazon Link](https://amzn.to/3FHea6D)
- **HX711 5kg Wägezellen-Verstärker:** Für Gewichtsmessung. - **HX711 5kg Load Cell Amplifier:** For weight measurement.
[Amazon Link](https://amzn.eu/d/06A0DLb) [Amazon Link](https://amzn.to/4ja1KTe)
- **OLED 0.96 Zoll I2C weiß/gelb Display:** 128x64 SSD1306. - **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306.
[Amazon Link](https://amzn.eu/d/0AuBp2c) [Amazon Link](https://amzn.to/445aaa9)
- **PN532 NFC NXP RFID-Modul V3:** Für NFC-Tag-Operationen. - **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations.
[Amazon Link](https://amzn.eu/d/jfIuQXb) [Amazon Link](https://amzn.to/4iO6CO4)
- **NFC Tags Ntag215:** RFID Tag - **NFC Tags NTAG213 NTAG215:** RFID Tag
[Amazon Link](https://amzn.eu/d/9Z6mXc1) [Amazon Link](https://amzn.to/3E071xO)
- **TTP223 Touch Sensor (optional):** For reTARE per Button/Touch
[Amazon Link](https://amzn.to/4hTChMK)
### Pin-Konfiguration
| Komponente | ESP32 Pin | ### Pin Konfiguration
| Component | ESP32 Pin |
|-------------------|-----------| |-------------------|-----------|
| HX711 DOUT | 16 | | HX711 DOUT | 16 |
| HX711 SCK | 17 | | HX711 SCK | 17 |
@ -75,8 +80,10 @@ Deutsches Erklärvideo: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaO
| PN532 RESET | 33 | | PN532 RESET | 33 |
| PN532 SDA | 21 | | PN532 SDA | 21 |
| PN532 SCL | 22 | | PN532 SCL | 22 |
| TTP223 I/O | 25 |
**Achte darauf, dass am PN532 die DIP-Schalter auf I2C gestellt sind** **!! Achte darauf, dass am PN532 die DIP-Schalter auf I2C gestellt sind**
**Nutze den 3V Pin vom ESP für den Touch Sensor**
![Wiring](./img/Schaltplan.png) ![Wiring](./img/Schaltplan.png)

View File

@ -6,12 +6,14 @@ FilaMan is a filament management system for 3D printing. It uses ESP32 hardware
Users can manage filament spools, monitor the status of the Automatic Material System (AMS) and make settings via a web interface. Users can manage filament spools, monitor the status of the Automatic Material System (AMS) and make settings via a web interface.
The system integrates seamlessly with [Bambulab](https://bambulab.com/en-us) 3D printers and [Spoolman](https://github.com/Donkie/Spoolman) filament management as well as the [Openspool](https://github.com/spuder/OpenSpool) NFC-TAG format. The system integrates seamlessly with [Bambulab](https://bambulab.com/en-us) 3D printers and [Spoolman](https://github.com/Donkie/Spoolman) filament management as well as the [Openspool](https://github.com/spuder/OpenSpool) NFC-TAG format.
![Scale](./img/scale_trans.png) ![Scale](./img/scale_trans.png)
More Images can be found in the [img Folder](/img/) More Images can be found in the [img Folder](/img/)
or my website:[FilaMan Website](https://www.filaman.app) or my website: [FilaMan Website](https://www.filaman.app)
german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU) german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62zaOHU)
Discord Server: [https://discord.gg/my7Gvaxj2v](https://discord.gg/my7Gvaxj2v)
### Now more detailed informations about the usage: [Wiki](https://github.com/ManuelW77/Filaman/wiki) ### Now more detailed informations about the usage: [Wiki](https://github.com/ManuelW77/Filaman/wiki)
@ -21,7 +23,7 @@ german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62z
- **OLED Display:** Shows current weight, connection status (WiFi, Bambu Lab, Spoolman). - **OLED Display:** Shows current weight, connection status (WiFi, Bambu Lab, Spoolman).
- **WiFi Connectivity:** WiFiManager for easy network configuration. - **WiFi Connectivity:** WiFiManager for easy network configuration.
- **MQTT Integration:** Connects to Bambu Lab printer for AMS control. - **MQTT Integration:** Connects to Bambu Lab printer for AMS control.
- **NFC-Tag NTAG215:** Use NTAG215 because of enaught space on the Tag - **NFC-Tag NTAG213 NTAG215:** Use NTAG213, better NTAG215 because of enaught space on the Tag
### Web Interface Features ### Web Interface Features
- **Real-time Updates:** WebSocket connection for live data updates. - **Real-time Updates:** WebSocket connection for live data updates.
@ -38,6 +40,7 @@ german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62z
- Filter and select filaments. - Filter and select filaments.
- Update spool weights automatically. - Update spool weights automatically.
- Track NFC tag assignments. - Track NFC tag assignments.
- Supports Spoolman Octoprint Plugin
### If you want to support my work, i would be happy to get a coffe ### If you want to support my work, i would be happy to get a coffe
<a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a> <a href="https://www.buymeacoffee.com/manuelw" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 30px !important;width: 108px !important;" ></a>
@ -57,15 +60,17 @@ german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62z
### Components ### Components
- **ESP32 Development Board:** Any ESP32 variant. - **ESP32 Development Board:** Any ESP32 variant.
[Amazon Link](https://amzn.eu/d/aXThslf) [Amazon Link](https://amzn.to/3FHea6D)
- **HX711 5kg Load Cell Amplifier:** For weight measurement. - **HX711 5kg Load Cell Amplifier:** For weight measurement.
[Amazon Link](https://amzn.eu/d/06A0DLb) [Amazon Link](https://amzn.to/4ja1KTe)
- **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306. - **OLED 0.96 Zoll I2C white/yellow Display:** 128x64 SSD1306.
[Amazon Link](https://amzn.eu/d/0AuBp2c) [Amazon Link](https://amzn.to/445aaa9)
- **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations. - **PN532 NFC NXP RFID-Modul V3:** For NFC tag operations.
[Amazon Link](https://amzn.eu/d/jfIuQXb) [Amazon Link](https://amzn.to/4iO6CO4)
- **NFC Tags Ntag215:** RFID Tag - **NFC Tags NTAG213 NTAG215:** RFID Tag
[Amazon Link](https://amzn.eu/d/9Z6mXc1) [Amazon Link](https://amzn.to/3E071xO)
- **TTP223 Touch Sensor (optional):** For reTARE per Button/Touch
[Amazon Link](https://amzn.to/4hTChMK)
### Pin Configuration ### Pin Configuration
@ -79,8 +84,10 @@ german explanatory video: [Youtube](https://youtu.be/uNDe2wh9SS8?si=b-jYx4I1w62z
| PN532 RESET | 33 | | PN532 RESET | 33 |
| PN532 SDA | 21 | | PN532 SDA | 21 |
| PN532 SCL | 22 | | PN532 SCL | 22 |
| TTP223 I/O | 25 |
**Make sure that the DIP switches on the PN532 are set to I2C** **!! Make sure that the DIP switches on the PN532 are set to I2C**
**Use the 3V pin from the ESP for the touch sensor**
![Wiring](./img/Schaltplan.png) ![Wiring](./img/Schaltplan.png)

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -141,15 +141,6 @@
</div> </div>
</div> </div>
<!-- Rechte Spalte -->
<div class="column">
<div class="feature-box">
<h2>Bambu AMS</h2>
<div id="amsDataContainer">
<div class="amsData" id="amsData">Wait for AMS-Data...</div>
</div>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -208,7 +208,7 @@ document.addEventListener('spoolmanError', function(event) {
showNotification(`Spoolman Error: ${event.detail.message}`, false); showNotification(`Spoolman Error: ${event.detail.message}`, false);
}); });
document.addEventListener('filamentSelected', function(event) { document.addEventListener('filamentSelected', function (event) {
updateNfcInfo(); updateNfcInfo();
// Zeige Spool-Buttons wenn ein Filament ausgewählt wurde // Zeige Spool-Buttons wenn ein Filament ausgewählt wurde
const selectedText = document.getElementById("selected-filament").textContent; const selectedText = document.getElementById("selected-filament").textContent;
@ -490,7 +490,7 @@ function handleSpoolIn(amsId, trayId) {
nozzle_temp_max: parseInt(maxTemp), nozzle_temp_max: parseInt(maxTemp),
type: selectedSpool.filament.material, type: selectedSpool.filament.material,
brand: selectedSpool.filament.vendor.name, brand: selectedSpool.filament.vendor.name,
tray_info_idx: selectedSpool.filament.extra.bambu_idx.replace(/['"]+/g, '').trim(), tray_info_idx: selectedSpool.filament.extra.bambu_idx?.replace(/['"]+/g, '').trim() || '',
cali_idx: "-1" // Default-Wert setzen cali_idx: "-1" // Default-Wert setzen
} }
}; };
@ -640,8 +640,6 @@ function writeNfcTag() {
// Erstelle das NFC-Datenpaket mit korrekten Datentypen // Erstelle das NFC-Datenpaket mit korrekten Datentypen
const nfcData = { const nfcData = {
version: "2.0",
protocol: "openspool",
color_hex: selectedSpool.filament.color_hex || "FFFFFF", color_hex: selectedSpool.filament.color_hex || "FFFFFF",
type: selectedSpool.filament.material, type: selectedSpool.filament.material,
min_temp: minTemp, min_temp: minTemp,

160
html/rfid_bambu.html Normal file
View File

@ -0,0 +1,160 @@
<!-- head --><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FilaMan - Filament Management Tool</title>
<link rel="icon" type="image/png" href="/favicon.ico">
<link rel="stylesheet" href="style.css">
<script>
fetch('/api/version')
.then(response => response.json())
.then(data => {
const versionSpan = document.querySelector('.version');
if (versionSpan) {
versionSpan.textContent = 'v' + data.version;
}
})
.catch(error => console.error('Error fetching version:', error));
</script>
</head>
<body>
<div class="navbar">
<div style="display: flex; align-items: center; gap: 2rem;">
<img src="/logo.png" alt="FilaMan Logo" class="logo">
<div class="logo-text">
<h1>FilaMan<span class="version"></span></h1>
<h4>Filament Management Tool</h4>
</div>
</div>
<nav style="display: flex; gap: 1rem;">
<a href="/">Start</a>
<a href="/waage">Scale</a>
<a href="/spoolman">Spoolman/Bambu</a>
<a href="/about">About</a>
<a href="/upgrade">Upgrade</a>
</nav>
<div class="status-container">
<div class="status-item">
<span class="status-dot" id="bambuDot"></span>B
</div>
<div class="status-item">
<span class="status-dot" id="spoolmanDot"></span>S
</div>
<div class="ram-status" id="ramStatus"></div>
</div>
</div>
<!-- head -->
<div class="connection-status hidden">
<div class="spinner"></div>
<span>Connection lost. Trying to reconnect...</span>
</div>
<div class="content">
<div class="three-column-layout">
<!-- Linke Spalte -->
<div class="column">
<div class="feature-box">
<div class="statistics-header">
<h2>Statistics</h2>
<button id="refreshSpoolman" class="refresh-button">
<span>Refresh Spoolman</span>
</button>
</div>
<div class="statistics-column">
<h3>Spools</h3>
<div class="spool-stat" style="display: flex; justify-content: center; align-items: center;">
<span class="stat-label">total:</span>
<span class="stat-value" id="totalSpools"></span>
<div style="width: auto;"></div>
<span class="stat-label">without Tag:</span>
<span class="stat-value" id="spoolsWithoutTag"></span>
</div>
</div>
<div class="statistics-grid">
<div class="statistics-column">
<h3>Overview</h3>
<ul class="statistics-list">
<li>
<span class="stat-label">Manufacturer:</span>
<span class="stat-value" id="totalVendors"></span>
</li>
<li>
<span class="stat-label">Weight:</span>
<span class="stat-value"><span id="totalWeight"></span></span>
</li>
<li>
<span class="stat-label">Length:</span>
<span class="stat-value"><span id="totalLength"></span></span>
</li>
</ul>
</div>
<div class="statistics-column">
<h3>Materials</h3>
<ul class="statistics-list" id="materialsList">
<!-- Wird dynamisch befüllt -->
</ul>
</div>
</div>
</div>
<div class="feature-box">
<div class="nfc-header">
<h2>NFC-Tag</h2>
<span id="nfcStatusIndicator" class="status-circle"></span>
</div>
<div class="nfc-status-display"></div>
</div>
</div>
<!-- Mittlere Spalte -->
<div class="column">
<div class="feature-box">
<h2>Spoolman Spools</h2>
<label for="vendorSelect">Manufacturer:</label>
<div style="display: flex; justify-content: space-between; align-items: center;">
<select id="vendorSelect" class="styled-select">
<option value="">Please choose...</option>
</select>
<label style="margin-left: 10px;">
<input type="checkbox" id="onlyWithoutSmId" checked onchange="updateFilamentDropdown()">
Only Spools without SM ID
</label>
</div>
</div>
<div id="filamentSection" class="feature-box hidden">
<label>Spool / Filament:</label>
<div class="custom-dropdown">
<div class="dropdown-button" onclick="toggleFilamentDropdown()">
<div class="selected-color" id="selected-color"></div>
<span id="selected-filament">Please choose...</span>
<span class="dropdown-arrow"></span>
</div>
<div class="dropdown-content" id="filament-dropdown-content">
<!-- Optionen werden dynamisch hinzugefügt -->
</div>
</div>
<p id="nfcInfo" class="nfc-status"></p>
<button id="writeNfcButton" class="btn btn-primary hidden" onclick="writeNfcTag()">Write Tag</button>
</div>
</div>
<!-- Rechte Spalte -->
<div class="column">
<div class="feature-box">
<h2>Bambu AMS</h2>
<div id="amsDataContainer">
<div class="amsData" id="amsData">Wait for AMS-Data...</div>
</div>
</div>
</div>
</div>
</div>
<script src="spoolman.js"></script>
<script src="rfid.js"></script>
</body>
</html>

View File

@ -52,11 +52,43 @@
if (spoolmanUrl && spoolmanUrl.trim() !== "") { if (spoolmanUrl && spoolmanUrl.trim() !== "") {
document.getElementById('spoolmanUrl').value = spoolmanUrl; document.getElementById('spoolmanUrl').value = spoolmanUrl;
} }
// Initialize OctoPrint fields visibility
toggleOctoFields();
}; };
function removeBambuCredentials() {
fetch('/api/bambu?remove=true')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('bambuIp').value = '';
document.getElementById('bambuSerial').value = '';
document.getElementById('bambuCode').value = '';
document.getElementById('autoSend').checked = false;
document.getElementById('autoSendTime').value = '';
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials removed!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing Bambu Credentials.';
}
})
.catch(error => {
document.getElementById('bambuStatusMessage').innerText = 'Error while removing: ' + error.message;
});
}
function checkSpoolmanInstance() { function checkSpoolmanInstance() {
const url = document.getElementById('spoolmanUrl').value; const url = document.getElementById('spoolmanUrl').value;
fetch(`/api/checkSpoolman?url=${encodeURIComponent(url)}`) const spoolmanOctoEnabled = document.getElementById('spoolmanOctoEnabled').checked;
const spoolmanOctoUrl = document.getElementById('spoolmanOctoUrl').value;
const spoolmanOctoToken = document.getElementById('spoolmanOctoToken').value;
fetch(`/api/checkSpoolman?url=${encodeURIComponent(url)}&octoEnabled=${spoolmanOctoEnabled}&octoUrl=${spoolmanOctoUrl}&octoToken=${spoolmanOctoToken}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.healthy) { if (data.healthy) {
@ -82,6 +114,11 @@
.then(data => { .then(data => {
if (data.healthy) { if (data.healthy) {
document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!'; document.getElementById('bambuStatusMessage').innerText = 'Bambu Credentials saved!';
// Reload with forced cache refresh after short delay
setTimeout(() => {
window.location.reload(true);
window.location.href = '/';
}, 1500);
} else { } else {
document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.'; document.getElementById('bambuStatusMessage').innerText = 'Error while saving Bambu Credentials.';
} }
@ -90,6 +127,15 @@
document.getElementById('bambuStatusMessage').innerText = 'Error while saving: ' + error.message; document.getElementById('bambuStatusMessage').innerText = 'Error while saving: ' + error.message;
}); });
} }
/**
* Controls visibility of OctoPrint configuration fields based on checkbox state
* Called on page load and when checkbox changes
*/
function toggleOctoFields() {
const octoEnabled = document.getElementById('spoolmanOctoEnabled').checked;
document.getElementById('octoFields').style.display = octoEnabled ? 'block' : 'none';
}
</script> </script>
<script> <script>
var spoolmanUrl = "{{spoolmanUrl}}"; var spoolmanUrl = "{{spoolmanUrl}}";
@ -102,6 +148,17 @@
<div class="card-body"> <div class="card-body">
<h5 class="card-title">Set URL/IP to your Spoolman-Instanz</h5> <h5 class="card-title">Set URL/IP to your Spoolman-Instanz</h5>
<input type="text" id="spoolmanUrl" placeholder="http://ip-or-url-of-your-spoolman-instanz:port"> <input type="text" id="spoolmanUrl" placeholder="http://ip-or-url-of-your-spoolman-instanz:port">
<h5 class="card-title">If you want to enable sending Spool to Spoolman Octoprint Plugin:</h5>
<p>
<input type="checkbox" id="spoolmanOctoEnabled" {{spoolmanOctoEnabled}} onchange="toggleOctoFields()"> Send to Octo-Plugin
</p>
<div id="octoFields" style="display: none;">
<p>
<input type="text" id="spoolmanOctoUrl" placeholder="http://ip-or-url-of-your-octoprint-instanz:port" value="{{spoolmanOctoUrl}}">
<input type="text" id="spoolmanOctoToken" placeholder="Your Octoprint Token" value="{{spoolmanOctoToken}}">
</p>
</div>
<button onclick="checkSpoolmanInstance()">Save Spoolman URL</button> <button onclick="checkSpoolmanInstance()">Save Spoolman URL</button>
<p id="statusMessage"></p> <p id="statusMessage"></p>
</div> </div>
@ -127,14 +184,15 @@
<p>If activated, FilaMan will automatically update the next filled tray with the last scanned and weighed spool.</p> <p>If activated, FilaMan will automatically update the next filled tray with the last scanned and weighed spool.</p>
<div class="input-group" style="display: flex; margin-bottom: 0;"> <div class="input-group" style="display: flex; margin-bottom: 0;">
<label for="autoSend" style="width: 250px; margin-right: 5px;">Auto Send to Bambu:</label> <label for="autoSend" style="width: 250px; margin-right: 5px;">Auto Send to Bambu:</label>
<label for="autoSendTime" style="width: 250px; margin-right: 5px;">Wait time in Seconds:</label> <label for="autoSendTime" style="width: 250px; margin-right: 5px;">Wait for Spool in Sec:</label>
</div> </div>
<div class="input-group" style="display: flex;"> <div class="input-group" style="display: flex;">
<input type="checkbox" id="autoSend" {{autoSendToBambu}} style="width: 190px; margin-right: 10px;"> <input type="checkbox" id="autoSend" {{autoSendToBambu}} style="width: 190px; margin-right: 10px;">
<input type="text" id="autoSendTime" placeholder="Time to wait for new Spool" value="{{autoSendTime}}" style="width: 100px;"> <input type="number" min="60" id="autoSendTime" placeholder="Time to wait" value="{{autoSendTime}}" style="width: 100px;">
</div> </div>
<button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button> <button style="margin: 0;" onclick="saveBambuCredentials()">Save Bambu Credentials</button>
<button style="margin: 0; background-color: red;" onclick="removeBambuCredentials()">Remove Credentials</button>
<p id="bambuStatusMessage"></p> <p id="bambuStatusMessage"></p>
</div> </div>
</div> </div>

View File

@ -86,10 +86,10 @@ function populateVendorDropdown(data, selectedSmId = null) {
}); });
// Nach der Schleife: Formatierung der Gesamtlänge // Nach der Schleife: Formatierung der Gesamtlänge
console.log("Total Lenght: ", totalLength); const lengthInM = totalLength / 1000; // erst in m umrechnen
const formattedLength = totalLength > 1000 const formattedLength = lengthInM > 1000
? (totalLength / 1000).toFixed(2) + " km" ? (lengthInM / 1000).toFixed(2) + " km"
: totalLength.toFixed(2) + " m"; : lengthInM.toFixed(2) + " m";
// Formatierung des Gesamtgewichts (von g zu kg zu t) // Formatierung des Gesamtgewichts (von g zu kg zu t)
const weightInKg = totalWeight / 1000; // erst in kg umrechnen const weightInKg = totalWeight / 1000; // erst in kg umrechnen
@ -97,8 +97,10 @@ function populateVendorDropdown(data, selectedSmId = null) {
? (weightInKg / 1000).toFixed(2) + " t" ? (weightInKg / 1000).toFixed(2) + " t"
: weightInKg.toFixed(2) + " kg"; : weightInKg.toFixed(2) + " kg";
// Dropdown mit gefilterten Herstellern befüllen // Dropdown mit gefilterten Herstellern befüllen - alphabetisch sortiert
Object.entries(filteredVendors).forEach(([id, name]) => { Object.entries(filteredVendors)
.sort(([, nameA], [, nameB]) => nameA.localeCompare(nameB)) // Sort vendors alphabetically by name
.forEach(([id, name]) => {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = id; option.value = id;
option.textContent = name; option.textContent = name;
@ -145,6 +147,13 @@ function updateFilamentDropdown(selectedSmId = null) {
if (vendorId) { if (vendorId) {
const filteredFilaments = spoolsData.filter(spool => { const filteredFilaments = spoolsData.filter(spool => {
if (!spool?.filament?.vendor?.id) {
console.log('Problem aufgetreten bei: ', spool?.filament?.vendor);
console.log('Problematische Spulen:',
spoolsData.filter(spool => !spool?.filament?.vendor?.id));
return false;
}
const hasValidNfcId = spool.extra && const hasValidNfcId = spool.extra &&
spool.extra.nfc_id && spool.extra.nfc_id &&
spool.extra.nfc_id !== '""' && spool.extra.nfc_id !== '""' &&
@ -238,18 +247,6 @@ async function fetchSpoolData() {
} }
} }
/*
// Exportiere Funktionen
window.getSpoolData = () => spoolsData;
window.reloadSpoolData = initSpoolman;
window.populateVendorDropdown = populateVendorDropdown;
window.updateFilamentDropdown = updateFilamentDropdown;
window.toggleFilamentDropdown = () => {
const content = document.getElementById("filament-dropdown-content");
content.classList.toggle("show");
};
*/
// Event Listener // Event Listener
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
initSpoolman(); initSpoolman();

View File

@ -188,14 +188,18 @@ label {
font-weight: bold; font-weight: bold;
} }
input[type="text"], input[type="submit"] { input[type="text"], input[type="submit"], input[type="number"] {
padding: 10px; padding: 10px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 5px; border-radius: 5px;
font-size: 16px; font-size: 16px;
} }
input[type="text"]:focus { input[type="number"] {
width: 108px !important;
}
input[type="text"]:focus, input[type="number"]:focus {
border-color: #007bff; border-color: #007bff;
outline: none; outline: none;
} }

View File

@ -129,6 +129,7 @@
if (data.status === 'success' || lastReceivedProgress >= 98) { if (data.status === 'success' || lastReceivedProgress >= 98) {
clearTimeout(wsReconnectTimer); clearTimeout(wsReconnectTimer);
setTimeout(() => { setTimeout(() => {
window.location.reload(true);
window.location.href = '/'; window.location.href = '/';
}, 30000); }, 30000);
} }
@ -148,6 +149,7 @@
status.style.display = 'block'; status.style.display = 'block';
clearTimeout(wsReconnectTimer); clearTimeout(wsReconnectTimer);
setTimeout(() => { setTimeout(() => {
window.location.reload(true);
window.location.href = '/'; window.location.href = '/';
}, 30000); }, 30000);
} else { } else {

View File

@ -55,6 +55,7 @@
<h5 class="card-title">Sacle Calibration</h5> <h5 class="card-title">Sacle Calibration</h5>
<button id="calibrateBtn" class="btn btn-primary">Calibrate Scale</button> <button id="calibrateBtn" class="btn btn-primary">Calibrate Scale</button>
<button id="tareBtn" class="btn btn-secondary">Tare Scale</button> <button id="tareBtn" class="btn btn-secondary">Tare Scale</button>
&nbsp;&nbsp;&nbsp;Enable Auto-TARE <input type="checkbox" id="autoTareCheckbox" onchange="setAutoTare(this.checked);" {{autoTare}}>
<div id="statusMessage" class="mt-3"></div> <div id="statusMessage" class="mt-3"></div>
</div> </div>
</div> </div>
@ -140,6 +141,15 @@
})); }));
}); });
// Add auto-tare function
function setAutoTare(enabled) {
ws.send(JSON.stringify({
type: 'scale',
payload: 'setAutoTare',
enabled: enabled
}));
}
// WebSocket-Verbindung beim Laden der Seite initiieren // WebSocket-Verbindung beim Laden der Seite initiieren
connectWebSocket(); connectWebSocket();
</script> </script>

BIN
img/7-enable.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -9,7 +9,9 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[common] [common]
version = "1.3.98" version = "1.5.1"
to_old_version = "1.5.0"
## ##
[env:esp32dev] [env:esp32dev]
platform = espressif32 platform = espressif32
@ -48,6 +50,7 @@ build_flags =
#-DNDEBUG #-DNDEBUG
-mtext-section-literals -mtext-section-literals
-DVERSION=\"${common.version}\" -DVERSION=\"${common.version}\"
-DTOOLDVERSION=\"${common.to_old_version}\"
-DASYNCWEBSERVER_REGEX -DASYNCWEBSERVER_REGEX
#-DCORE_DEBUG_LEVEL=3 #-DCORE_DEBUG_LEVEL=3
-DCONFIG_ARDUHAL_LOG_COLORS=1 -DCONFIG_ARDUHAL_LOG_COLORS=1

View File

@ -14,7 +14,7 @@ def copy_file(input_file, output_file):
def should_compress(file): def should_compress(file):
# Skip compression for spoolman.html # Skip compression for spoolman.html
if file == 'spoolman.html': if file == 'spoolman.html' or file == 'waage.html':
return False return False
# Komprimiere nur bestimmte Dateitypen # Komprimiere nur bestimmte Dateitypen
return file.endswith(('.js', '.png', '.css', '.html')) return file.endswith(('.js', '.png', '.css', '.html'))

View File

@ -3,13 +3,18 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include "commonFS.h" #include "commonFS.h"
bool spoolman_connected = false; volatile spoolmanApiStateType spoolmanApiState = API_INIT;
//bool spoolman_connected = false;
String spoolmanUrl = ""; String spoolmanUrl = "";
bool octoEnabled = false;
String octoUrl = "";
String octoToken = "";
struct SendToApiParams { struct SendToApiParams {
String httpType; String httpType;
String spoolsUrl; String spoolsUrl;
String updatePayload; String updatePayload;
String octoToken;
}; };
JsonDocument fetchSingleSpoolInfo(int spoolId) { JsonDocument fetchSingleSpoolInfo(int spoolId) {
@ -81,20 +86,26 @@ JsonDocument fetchSingleSpoolInfo(int spoolId) {
} }
void sendToApi(void *parameter) { void sendToApi(void *parameter) {
spoolmanApiState = API_TRANSMITTING;
SendToApiParams* params = (SendToApiParams*)parameter; SendToApiParams* params = (SendToApiParams*)parameter;
// Extrahiere die Werte // Extrahiere die Werte
String httpType = params->httpType; String httpType = params->httpType;
String spoolsUrl = params->spoolsUrl; String spoolsUrl = params->spoolsUrl;
String updatePayload = params->updatePayload; String updatePayload = params->updatePayload;
String octoToken = params->octoToken;
HTTPClient http; HTTPClient http;
http.setReuse(false);
http.begin(spoolsUrl); http.begin(spoolsUrl);
http.addHeader("Content-Type", "application/json"); http.addHeader("Content-Type", "application/json");
if (octoEnabled && octoToken != "") http.addHeader("X-Api-Key", octoToken);
int httpCode = http.PUT(updatePayload); int httpCode;
if (httpType == "PATCH") httpCode = http.PATCH(updatePayload); if (httpType == "PATCH") httpCode = http.PATCH(updatePayload);
else if (httpType == "POST") httpCode = http.POST(updatePayload);
else httpCode = http.PUT(updatePayload);
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
Serial.println("Spoolman erfolgreich aktualisiert"); Serial.println("Spoolman erfolgreich aktualisiert");
@ -105,10 +116,12 @@ void sendToApi(void *parameter) {
} }
http.end(); http.end();
vTaskDelay(50 / portTICK_PERIOD_MS);
// Speicher freigeben // Speicher freigeben
delete params; delete params;
vTaskDelete(NULL); vTaskDelete(NULL);
spoolmanApiState = API_IDLE;
} }
bool updateSpoolTagId(String uidString, const char* payload) { bool updateSpoolTagId(String uidString, const char* payload) {
@ -153,12 +166,14 @@ bool updateSpoolTagId(String uidString, const char* payload) {
BaseType_t result = xTaskCreate( BaseType_t result = xTaskCreate(
sendToApi, // Task-Funktion sendToApi, // Task-Funktion
"SendToApiTask", // Task-Name "SendToApiTask", // Task-Name
4096, // Stackgröße in Bytes 6144, // Stackgröße in Bytes
(void*)params, // Parameter (void*)params, // Parameter
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return true; return true;
} }
@ -189,15 +204,56 @@ uint8_t updateSpoolWeight(String spoolId, uint16_t weight) {
BaseType_t result = xTaskCreate( BaseType_t result = xTaskCreate(
sendToApi, // Task-Funktion sendToApi, // Task-Funktion
"SendToApiTask", // Task-Name "SendToApiTask", // Task-Name
4096, // Stackgröße in Bytes 6144, // Stackgröße in Bytes
(void*)params, // Parameter (void*)params, // Parameter
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
); );
updateDoc.clear();
return 1; return 1;
} }
bool updateSpoolOcto(int spoolId) {
String spoolsUrl = octoUrl + "/plugin/Spoolman/selectSpool";
Serial.print("Update Spule in Octoprint mit URL: ");
Serial.println(spoolsUrl);
JsonDocument updateDoc;
updateDoc["spool_id"] = spoolId;
updateDoc["tool"] = "tool0";
String updatePayload;
serializeJson(updateDoc, updatePayload);
Serial.print("Update Payload: ");
Serial.println(updatePayload);
SendToApiParams* params = new SendToApiParams();
if (params == nullptr) {
Serial.println("Fehler: Kann Speicher für Task-Parameter nicht allokieren.");
return false;
}
params->httpType = "POST";
params->spoolsUrl = spoolsUrl;
params->updatePayload = updatePayload;
params->octoToken = octoToken;
// Erstelle die Task
BaseType_t result = xTaskCreate(
sendToApi, // Task-Funktion
"SendToApiTask", // Task-Name
6144, // Stackgröße in Bytes
(void*)params, // Parameter
0, // Priorität
NULL // Task-Handle (nicht benötigt)
);
updateDoc.clear();
return true;
}
bool updateSpoolBambuData(String payload) { bool updateSpoolBambuData(String payload) {
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeJson(doc, payload); DeserializationError error = deserializeJson(doc, payload);
@ -235,7 +291,7 @@ bool updateSpoolBambuData(String payload) {
BaseType_t result = xTaskCreate( BaseType_t result = xTaskCreate(
sendToApi, // Task-Funktion sendToApi, // Task-Funktion
"SendToApiTask", // Task-Name "SendToApiTask", // Task-Name
4096, // Stackgröße in Bytes 6144, // Stackgröße in Bytes
(void*)params, // Parameter (void*)params, // Parameter
0, // Priorität 0, // Priorität
NULL // Task-Handle (nicht benötigt) NULL // Task-Handle (nicht benötigt)
@ -426,7 +482,8 @@ bool checkSpoolmanInstance(const String& url) {
return false; return false;
} }
spoolman_connected = true; spoolmanApiState = API_IDLE;
oledShowTopRow();
return strcmp(status, "healthy") == 0; return strcmp(status, "healthy") == 0;
} }
} }
@ -435,17 +492,24 @@ bool checkSpoolmanInstance(const String& url) {
return false; return false;
} }
bool saveSpoolmanUrl(const String& url) { bool saveSpoolmanUrl(const String& url, bool octoOn, const String& octoWh, const String& octoTk) {
if (!checkSpoolmanInstance(url)) return false; if (!checkSpoolmanInstance(url)) return false;
JsonDocument doc; JsonDocument doc;
doc["url"] = url; doc["url"] = url;
Serial.print("Speichere URL in Datei: "); doc["octoEnabled"] = octoOn;
Serial.println(url); doc["octoUrl"] = octoWh;
doc["octoToken"] = octoTk;
Serial.print("Speichere Spoolman Data in Datei: ");
Serial.println(doc.as<String>());
if (!saveJsonValue("/spoolman_url.json", doc)) { if (!saveJsonValue("/spoolman_url.json", doc)) {
Serial.println("Fehler beim Speichern der Spoolman-URL."); Serial.println("Fehler beim Speichern der Spoolman-URL.");
return false;
} }
spoolmanUrl = url; spoolmanUrl = url;
octoEnabled = octoOn;
octoUrl = octoWh;
octoToken = octoTk;
return true; return true;
} }
@ -453,6 +517,13 @@ bool saveSpoolmanUrl(const String& url) {
String loadSpoolmanUrl() { String loadSpoolmanUrl() {
JsonDocument doc; JsonDocument doc;
if (loadJsonValue("/spoolman_url.json", doc) && doc["url"].is<String>()) { if (loadJsonValue("/spoolman_url.json", doc) && doc["url"].is<String>()) {
octoEnabled = (doc["octoEnabled"].is<bool>()) ? doc["octoEnabled"].as<bool>() : false;
if (octoEnabled && doc["octoToken"].is<String>() && doc["octoUrl"].is<String>())
{
octoUrl = doc["octoUrl"].as<String>();
octoToken = doc["octoToken"].as<String>();
}
return doc["url"].as<String>(); return doc["url"].as<String>();
} }
Serial.println("Keine gültige Spoolman-URL gefunden."); Serial.println("Keine gültige Spoolman-URL gefunden.");

View File

@ -6,12 +6,21 @@
#include "website.h" #include "website.h"
#include "display.h" #include "display.h"
#include <ArduinoJson.h> #include <ArduinoJson.h>
typedef enum {
API_INIT,
API_IDLE,
API_TRANSMITTING
} spoolmanApiStateType;
extern volatile spoolmanApiStateType spoolmanApiState;
extern bool spoolman_connected; extern bool spoolman_connected;
extern String spoolmanUrl; extern String spoolmanUrl;
extern bool octoEnabled;
extern String octoUrl;
extern String octoToken;
bool checkSpoolmanInstance(const String& url); bool checkSpoolmanInstance(const String& url);
bool saveSpoolmanUrl(const String& url); bool saveSpoolmanUrl(const String& url, bool octoOn, const String& octoWh, const String& octoTk);
String loadSpoolmanUrl(); // Neue Funktion zum Laden der URL String loadSpoolmanUrl(); // Neue Funktion zum Laden der URL
bool checkSpoolmanExtraFields(); // Neue Funktion zum Überprüfen der Extrafelder bool checkSpoolmanExtraFields(); // Neue Funktion zum Überprüfen der Extrafelder
JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite JsonDocument fetchSingleSpoolInfo(int spoolId); // API-Funktion für die Webseite
@ -19,5 +28,6 @@ bool updateSpoolTagId(String uidString, const char* payload); // Neue Funktion z
uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts uint8_t updateSpoolWeight(String spoolId, uint16_t weight); // Neue Funktion zum Aktualisieren des Gewichts
bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman bool initSpoolman(); // Neue Funktion zum Initialisieren von Spoolman
bool updateSpoolBambuData(String payload); // Neue Funktion zum Aktualisieren der Bambu-Daten bool updateSpoolBambuData(String payload); // Neue Funktion zum Aktualisieren der Bambu-Daten
bool updateSpoolOcto(int spoolId); // Neue Funktion zum Aktualisieren der Octo-Daten
#endif #endif

View File

@ -17,7 +17,7 @@ PubSubClient client(sslClient);
TaskHandle_t BambuMqttTask; TaskHandle_t BambuMqttTask;
String report_topic = ""; String topic = "";
//String request_topic = ""; //String request_topic = "";
const char* bambu_username = "bblp"; const char* bambu_username = "bblp";
const char* bambu_ip = nullptr; const char* bambu_ip = nullptr;
@ -27,6 +27,7 @@ const char* bambu_serialnr = nullptr;
String g_bambu_ip = ""; String g_bambu_ip = "";
String g_bambu_accesscode = ""; String g_bambu_accesscode = "";
String g_bambu_serialnr = ""; String g_bambu_serialnr = "";
bool bambuDisabled = false;
bool bambu_connected = false; bool bambu_connected = false;
bool autoSendToBambu = false; bool autoSendToBambu = false;
@ -37,6 +38,32 @@ int ams_count = 0;
String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients String amsJsonData; // Speichert das fertige JSON für WebSocket-Clients
AMSData ams_data[MAX_AMS]; // Definition des Arrays; AMSData ams_data[MAX_AMS]; // Definition des Arrays;
bool removeBambuCredentials() {
if (BambuMqttTask) {
vTaskDelete(BambuMqttTask);
}
if (!removeJsonValue("/bambu_credentials.json")) {
Serial.println("Fehler beim Löschen der Bambu-Credentials.");
return false;
}
// Löschen der globalen Variablen
g_bambu_ip = "";
g_bambu_accesscode = "";
g_bambu_serialnr = "";
bambu_ip = nullptr;
bambu_accesscode = nullptr;
bambu_serialnr = nullptr;
autoSendToBambu = false;
autoSetToBambuSpoolId = 0;
ams_count = 0;
amsJsonData = "";
bambuDisabled = true;
return true;
}
bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) { bool saveBambuCredentials(const String& ip, const String& serialnr, const String& accesscode, bool autoSend, const String& autoSendTime) {
if (BambuMqttTask) { if (BambuMqttTask) {
vTaskDelete(BambuMqttTask); vTaskDelete(BambuMqttTask);
@ -91,7 +118,7 @@ bool loadBambuCredentials() {
bambu_accesscode = g_bambu_accesscode.c_str(); bambu_accesscode = g_bambu_accesscode.c_str();
bambu_serialnr = g_bambu_serialnr.c_str(); bambu_serialnr = g_bambu_serialnr.c_str();
report_topic = "device/" + String(bambu_serialnr) + "/report"; topic = "device/" + String(bambu_serialnr);
//request_topic = "device/" + String(bambu_serialnr) + "/request"; //request_topic = "device/" + String(bambu_serialnr) + "/request";
return true; return true;
} }
@ -199,7 +226,7 @@ FilamentResult findFilamentIdx(String brand, String type) {
bool sendMqttMessage(const String& payload) { bool sendMqttMessage(const String& payload) {
Serial.println("Sending MQTT message"); Serial.println("Sending MQTT message");
Serial.println(payload); Serial.println(payload);
if (client.publish(report_topic.c_str(), payload.c_str())) if (client.publish((String(topic) + "/request").c_str(), payload.c_str()))
{ {
return true; return true;
} }
@ -341,7 +368,7 @@ void updateAmsWsData(JsonDocument& doc, JsonArray& amsArray, int& ams_count, Jso
ams_data[i].trays[j].tray_color = trayObj["tray_color"].as<String>(); ams_data[i].trays[j].tray_color = trayObj["tray_color"].as<String>();
ams_data[i].trays[j].nozzle_temp_min = trayObj["nozzle_temp_min"].as<int>(); ams_data[i].trays[j].nozzle_temp_min = trayObj["nozzle_temp_min"].as<int>();
ams_data[i].trays[j].nozzle_temp_max = trayObj["nozzle_temp_max"].as<int>(); ams_data[i].trays[j].nozzle_temp_max = trayObj["nozzle_temp_max"].as<int>();
//ams_data[i].trays[j].setting_id = trayObj["setting_id"].as<String>(); if (trayObj["tray_type"].as<String>() == "") ams_data[i].trays[j].setting_id = "";
ams_data[i].trays[j].cali_idx = trayObj["cali_idx"].as<String>(); ams_data[i].trays[j].cali_idx = trayObj["cali_idx"].as<String>();
} }
} }
@ -425,16 +452,8 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
return; return;
} }
// Wenn bambu auto set spool aktiv und eine spule erkannt und mqtt meldung das neue spule im ams
if (autoSendToBambu && autoSetToBambuSpoolId > 0 &&
doc["print"]["command"].as<String>() == "push_status" && doc["print"]["ams"]["tray_pre"].as<uint8_t>()
&& !doc["print"]["ams"]["ams"].as<JsonArray>())
{
autoSetSpool(autoSetToBambuSpoolId, doc["print"]["ams"]["tray_pre"].as<uint8_t>());
}
// Prüfen, ob "print->upgrade_state" und "print.ams.ams" existieren // Prüfen, ob "print->upgrade_state" und "print.ams.ams" existieren
if (doc["print"]["upgrade_state"].is<JsonObject>()) if (doc["print"]["upgrade_state"].is<JsonObject>() || (doc["print"]["command"].is<String>() && doc["print"]["command"] == "push_status"))
{ {
// Prüfen ob AMS-Daten vorhanden sind // Prüfen ob AMS-Daten vorhanden sind
if (!doc["print"]["ams"].is<JsonObject>() || !doc["print"]["ams"]["ams"].is<JsonArray>()) if (!doc["print"]["ams"].is<JsonObject>() || !doc["print"]["ams"]["ams"].is<JsonArray>())
@ -479,6 +498,12 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
(trayObj["setting_id"].as<String>() != "" && trayObj["setting_id"].as<String>() != ams_data[storedIndex].trays[j].setting_id) || (trayObj["setting_id"].as<String>() != "" && trayObj["setting_id"].as<String>() != ams_data[storedIndex].trays[j].setting_id) ||
trayObj["cali_idx"].as<String>() != ams_data[storedIndex].trays[j].cali_idx) { trayObj["cali_idx"].as<String>() != ams_data[storedIndex].trays[j].cali_idx) {
hasChanges = true; hasChanges = true;
if (autoSendToBambu && autoSetToBambuSpoolId > 0 && hasChanges)
{
autoSetSpool(autoSetToBambuSpoolId, ams_data[storedIndex].trays[j].id);
}
break; break;
} }
} }
@ -497,6 +522,11 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
(vtTray["setting_id"].as<String>() != "" && vtTray["setting_id"].as<String>() != ams_data[i].trays[0].setting_id) || (vtTray["setting_id"].as<String>() != "" && vtTray["setting_id"].as<String>() != ams_data[i].trays[0].setting_id) ||
(vtTray["tray_type"].as<String>() != "" && vtTray["cali_idx"].as<String>() != ams_data[i].trays[0].cali_idx)) { (vtTray["tray_type"].as<String>() != "" && vtTray["cali_idx"].as<String>() != ams_data[i].trays[0].cali_idx)) {
hasChanges = true; hasChanges = true;
if (autoSendToBambu && autoSetToBambuSpoolId > 0 && hasChanges)
{
autoSetSpool(autoSetToBambuSpoolId, 254);
}
} }
break; break;
} }
@ -550,10 +580,11 @@ void reconnect() {
oledShowTopRow(); oledShowTopRow();
// Attempt to connect // Attempt to connect
if (client.connect(bambu_serialnr, bambu_username, bambu_accesscode)) { String clientId = String(bambu_serialnr) + "_" + String(random(0, 100));
if (client.connect(clientId.c_str(), bambu_username, bambu_accesscode)) {
Serial.println("MQTT re/connected"); Serial.println("MQTT re/connected");
client.subscribe(report_topic.c_str()); client.subscribe((String(topic) + "/report").c_str());
bambu_connected = true; bambu_connected = true;
oledShowTopRow(); oledShowTopRow();
} else { } else {
@ -600,30 +631,27 @@ void mqtt_loop(void * parameter) {
bool setupMqtt() { bool setupMqtt() {
// Wenn Bambu Daten vorhanden // Wenn Bambu Daten vorhanden
bool success = loadBambuCredentials(); bool success = loadBambuCredentials();
vTaskDelay(100 / portTICK_PERIOD_MS);
if (!success) { if (!success) {
Serial.println("Failed to load Bambu credentials"); bambuDisabled = true;
oledShowMessage("Bambu Credentials Missing");
vTaskDelay(2000 / portTICK_PERIOD_MS);
return false; return false;
} }
if (success && bambu_ip != "" && bambu_accesscode != "" && bambu_serialnr != "") if (success && bambu_ip != "" && bambu_accesscode != "" && bambu_serialnr != "")
{ {
bambuDisabled = false;
sslClient.setCACert(root_ca); sslClient.setCACert(root_ca);
sslClient.setInsecure(); sslClient.setInsecure();
client.setServer(bambu_ip, 8883); client.setServer(bambu_ip, 8883);
// Verbinden mit dem MQTT-Server // Verbinden mit dem MQTT-Server
bool connected = true; bool connected = true;
if (client.connect(bambu_serialnr, bambu_username, bambu_accesscode)) String clientId = String(bambu_serialnr) + "_" + String(random(0, 100));
if (client.connect(clientId.c_str(), bambu_username, bambu_accesscode))
{ {
client.setCallback(mqtt_callback); client.setCallback(mqtt_callback);
client.setBufferSize(5120); client.setBufferSize(15488);
// Optional: Topic abonnieren client.subscribe((String(topic) + "/report").c_str());
client.subscribe(report_topic.c_str());
//client.subscribe(request_topic.c_str());
Serial.println("MQTT-Client initialisiert"); Serial.println("MQTT-Client initialisiert");
oledShowMessage("Bambu Connected"); oledShowMessage("Bambu Connected");
@ -652,10 +680,7 @@ bool setupMqtt() {
} }
else else
{ {
Serial.println("Fehler: Keine MQTT-Daten vorhanden"); bambuDisabled = true;
oledShowMessage("Bambu Credentials Missing");
oledShowTopRow();
vTaskDelay(2000 / portTICK_PERIOD_MS);
return false; return false;
} }
return true; return true;
@ -664,6 +689,7 @@ bool setupMqtt() {
void bambu_restart() { void bambu_restart() {
if (BambuMqttTask) { if (BambuMqttTask) {
vTaskDelete(BambuMqttTask); vTaskDelete(BambuMqttTask);
delay(10);
} }
setupMqtt(); setupMqtt();
} }

View File

@ -30,7 +30,9 @@ extern int ams_count;
extern AMSData ams_data[MAX_AMS]; extern AMSData ams_data[MAX_AMS];
extern bool autoSendToBambu; extern bool autoSendToBambu;
extern int autoSetToBambuSpoolId; extern int autoSetToBambuSpoolId;
extern bool bambuDisabled;
bool removeBambuCredentials();
bool loadBambuCredentials(); bool loadBambuCredentials();
bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime); bool saveBambuCredentials(const String& bambu_ip, const String& bambu_serialnr, const String& bambu_accesscode, const bool autoSend, const String& autoSendTime);
bool setupMqtt(); bool setupMqtt();

View File

@ -1,6 +1,20 @@
#include "commonFS.h" #include "commonFS.h"
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char* filename) {
File file = LittleFS.open(filename, "r");
if (!file) {
return true;
}
file.close();
if (!LittleFS.remove(filename)) {
Serial.print("Fehler beim Löschen der Datei: ");
Serial.println(filename);
return false;
}
return true;
}
bool saveJsonValue(const char* filename, const JsonDocument& doc) { bool saveJsonValue(const char* filename, const JsonDocument& doc) {
File file = LittleFS.open(filename, "w"); File file = LittleFS.open(filename, "w");
if (!file) { if (!file) {

View File

@ -5,6 +5,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <LittleFS.h> #include <LittleFS.h>
bool removeJsonValue(const char* filename);
bool saveJsonValue(const char* filename, const JsonDocument& doc); bool saveJsonValue(const char* filename, const JsonDocument& doc);
bool loadJsonValue(const char* filename, JsonDocument& doc); bool loadJsonValue(const char* filename, JsonDocument& doc);
void initializeFileSystem(); void initializeFileSystem();

View File

@ -19,6 +19,12 @@ const uint16_t SCALE_LEVEL_WEIGHT = 500;
uint16_t defaultScaleCalibrationValue = 430; uint16_t defaultScaleCalibrationValue = 430;
// ***** HX711 // ***** HX711
// ***** TTP223 (Touch Sensor)
// TTP223 circuit wiring
const uint8_t TTP223_PIN = 25;
// ***** TTP223
// ***** Display // ***** Display
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// On an ESP32: 21(SDA), 22(SCL) // On an ESP32: 21(SDA), 22(SCL)

View File

@ -11,6 +11,8 @@ extern const uint8_t LOADCELL_SCK_PIN;
extern const uint8_t calVal_eepromAdress; extern const uint8_t calVal_eepromAdress;
extern const uint16_t SCALE_LEVEL_WEIGHT; extern const uint16_t SCALE_LEVEL_WEIGHT;
extern const uint8_t TTP223_PIN;
extern const int8_t OLED_RESET; extern const int8_t OLED_RESET;
extern const uint8_t SCREEN_ADDRESS; extern const uint8_t SCREEN_ADDRESS;
extern const uint8_t SCREEN_WIDTH; extern const uint8_t SCREEN_WIDTH;

View File

@ -177,7 +177,7 @@ void oledShowTopRow() {
display.drawBitmap(50, 0, bitmap_off , 16, 16, WHITE); display.drawBitmap(50, 0, bitmap_off , 16, 16, WHITE);
} }
if (spoolman_connected == 1) { if (spoolmanApiState != API_INIT) {
display.drawBitmap(80, 0, bitmap_spoolman_on , 16, 16, WHITE); display.drawBitmap(80, 0, bitmap_spoolman_on , 16, 16, WHITE);
} else { } else {
display.drawBitmap(80, 0, bitmap_off , 16, 16, WHITE); display.drawBitmap(80, 0, bitmap_off , 16, 16, WHITE);

View File

@ -13,6 +13,10 @@
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "commonFS.h" #include "commonFS.h"
bool mainTaskWasPaused = 0;
uint8_t scaleTareCounter = 0;
bool touchSensorConnected = false;
// ##### SETUP ##### // ##### SETUP #####
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -36,7 +40,6 @@ void setup() {
setupWebserver(server); setupWebserver(server);
// Spoolman API // Spoolman API
// api.cpp
initSpoolman(); initSpoolman();
// Bambu MQTT // Bambu MQTT
@ -45,32 +48,23 @@ void setup() {
// NFC Reader // NFC Reader
startNfc(); startNfc();
uint8_t scaleCalibrated = start_scale(); // Touch Sensor
if (scaleCalibrated == 3) { pinMode(TTP223_PIN, INPUT_PULLUP);
oledShowMessage("Scale not calibrated!"); if (digitalRead(TTP223_PIN) == LOW)
for (uint16_t i = 0; i < 50000; i++) { {
yield(); Serial.println("Touch Sensor is connected");
vTaskDelay(pdMS_TO_TICKS(1)); touchSensorConnected = true;
esp_task_wdt_reset();
}
} else if (scaleCalibrated == 0) {
oledShowMessage("HX711 not found");
for (uint16_t i = 0; i < 50000; i++) {
yield();
vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset();
}
} }
// Scale
start_scale(touchSensorConnected);
// WDT initialisieren mit 10 Sekunden Timeout // WDT initialisieren mit 10 Sekunden Timeout
bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus bool panic = true; // Wenn true, löst ein WDT-Timeout einen System-Panik aus
esp_task_wdt_init(10, panic); esp_task_wdt_init(10, panic);
// Aktuellen Task (loopTask) zum Watchdog hinzufügen // Aktuellen Task (loopTask) zum Watchdog hinzufügen
esp_task_wdt_add(NULL); esp_task_wdt_add(NULL);
// Optional: Andere Tasks zum Watchdog hinzufügen, falls nötig
// esp_task_wdt_add(task_handle);
} }
@ -99,23 +93,42 @@ uint8_t autoAmsCounter = 0;
uint8_t weightSend = 0; uint8_t weightSend = 0;
int16_t lastWeight = 0; int16_t lastWeight = 0;
// WIFI check variables
unsigned long lastWifiCheckTime = 0; unsigned long lastWifiCheckTime = 0;
const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms) const unsigned long wifiCheckInterval = 60000; // Überprüfe alle 60 Sekunden (60000 ms)
// Button debounce variables
unsigned long lastButtonPress = 0;
const unsigned long debounceDelay = 500; // 500 ms debounce delay
// ##### PROGRAM START ##### // ##### PROGRAM START #####
void loop() { void loop() {
unsigned long currentMillis = millis(); unsigned long currentMillis = millis();
// Überprüfe den Status des Touch Sensors
if (touchSensorConnected && digitalRead(TTP223_PIN) == HIGH && currentMillis - lastButtonPress > debounceDelay)
{
lastButtonPress = currentMillis;
scaleTareRequest = true;
}
// Überprüfe regelmäßig die WLAN-Verbindung // Überprüfe regelmäßig die WLAN-Verbindung
if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval)) { if (intervalElapsed(currentMillis, lastWifiCheckTime, wifiCheckInterval))
{
checkWiFiConnection(); checkWiFiConnection();
} }
// Wenn Bambu auto set Spool aktiv // Wenn Bambu auto set Spool aktiv
if (autoSendToBambu && autoSetToBambuSpoolId > 0) { if (autoSendToBambu && autoSetToBambuSpoolId > 0)
{
if (!bambuDisabled && !bambu_connected)
{
bambu_restart();
}
if (intervalElapsed(currentMillis, lastAutoSetBambuAmsTime, autoSetBambuAmsInterval)) if (intervalElapsed(currentMillis, lastAutoSetBambuAmsTime, autoSetBambuAmsInterval))
{ {
if (hasReadRfidTag == 0) if (nfcReaderState == NFC_IDLE)
{ {
lastAutoSetBambuAmsTime = currentMillis; lastAutoSetBambuAmsTime = currentMillis;
oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s"); oledShowMessage("Auto Set " + String(autoSetBambuAmsCounter - autoAmsCounter) + "s");
@ -147,19 +160,28 @@ void loop() {
} }
// Ausgabe der Waage auf Display // Ausgabe der Waage auf Display
if (pauseMainTask == 0 && weight != lastWeight && hasReadRfidTag == 0 && (!autoSendToBambu || autoSetToBambuSpoolId == 0)) if(pauseMainTask == 0)
{
if (mainTaskWasPaused || (weight != lastWeight && nfcReaderState == NFC_IDLE && (!autoSendToBambu || autoSetToBambuSpoolId == 0)))
{ {
(weight < 2) ? ((weight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(weight); (weight < 2) ? ((weight < -2) ? oledShowMessage("!! -0") : oledShowWeight(0)) : oledShowWeight(weight);
} }
mainTaskWasPaused = false;
}
else
{
mainTaskWasPaused = true;
}
// Wenn Timer abgelaufen und nicht gerade ein RFID-Tag geschrieben wird // Wenn Timer abgelaufen und nicht gerade ein RFID-Tag geschrieben wird
if (currentMillis - lastWeightReadTime >= weightReadInterval && hasReadRfidTag < 3) if (currentMillis - lastWeightReadTime >= weightReadInterval && nfcReaderState < NFC_WRITING)
{ {
lastWeightReadTime = currentMillis; lastWeightReadTime = currentMillis;
// Prüfen ob die Waage korrekt genullt ist // Prüfen ob die Waage korrekt genullt ist
if ((weight > 0 && weight < 5) || weight < 0) // Abweichung von 2g ignorieren
if (autoTare && (weight > 2 && weight < 7) || weight < -2)
{ {
scale_tare_counter++; scale_tare_counter++;
} }
@ -169,7 +191,7 @@ void loop() {
} }
// Prüfen ob das Gewicht gleich bleibt und dann senden // Prüfen ob das Gewicht gleich bleibt und dann senden
if (weight == lastWeight && weight > 5) if (abs(weight - lastWeight) <= 2 && weight > 5)
{ {
weigthCouterToApi++; weigthCouterToApi++;
} }
@ -181,7 +203,8 @@ void loop() {
} }
// reset weight counter after writing tag // reset weight counter after writing tag
if (currentMillis - lastWeightReadTime >= weightReadInterval && hasReadRfidTag > 1) // TBD: what exactly is the logic behind this?
if (currentMillis - lastWeightReadTime >= weightReadInterval && nfcReaderState != NFC_IDLE && nfcReaderState != NFC_READ_SUCCESS)
{ {
weigthCouterToApi = 0; weigthCouterToApi = 0;
} }
@ -189,7 +212,7 @@ void loop() {
lastWeight = weight; lastWeight = weight;
// Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden // Wenn ein Tag mit SM id erkannte wurde und der Waage Counter anspricht an SM Senden
if (spoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && hasReadRfidTag == 1) { if (spoolId != "" && weigthCouterToApi > 3 && weightSend == 0 && nfcReaderState == NFC_READ_SUCCESS) {
oledShowIcon("loading"); oledShowIcon("loading");
if (updateSpoolWeight(spoolId, weight)) if (updateSpoolWeight(spoolId, weight))
{ {
@ -197,6 +220,11 @@ void loop() {
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
weightSend = 1; weightSend = 1;
autoSetToBambuSpoolId = spoolId.toInt(); autoSetToBambuSpoolId = spoolId.toInt();
if (octoEnabled)
{
updateSpoolOcto(autoSetToBambuSpoolId);
}
} }
else else
{ {
@ -205,6 +233,5 @@ void loop() {
} }
} }
yield();
esp_task_wdt_reset(); esp_task_wdt_reset();
} }

View File

@ -18,7 +18,7 @@ String spoolId = "";
String nfcJsonData = ""; String nfcJsonData = "";
volatile bool pauseBambuMqttTask = false; volatile bool pauseBambuMqttTask = false;
volatile uint8_t hasReadRfidTag = 0; volatile nfcReaderStateType nfcReaderState = NFC_IDLE;
// 0 = nicht gelesen // 0 = nicht gelesen
// 1 = erfolgreich gelesen // 1 = erfolgreich gelesen
// 2 = fehler beim Lesen // 2 = fehler beim Lesen
@ -44,8 +44,6 @@ void payloadToJson(uint8_t *data) {
DeserializationError error = deserializeJson(doc, jsonString); DeserializationError error = deserializeJson(doc, jsonString);
if (!error) { if (!error) {
const char* version = doc["version"];
const char* protocol = doc["protocol"];
const char* color_hex = doc["color_hex"]; const char* color_hex = doc["color_hex"];
const char* type = doc["type"]; const char* type = doc["type"];
int min_temp = doc["min_temp"]; int min_temp = doc["min_temp"];
@ -55,8 +53,6 @@ void payloadToJson(uint8_t *data) {
Serial.println(); Serial.println();
Serial.println("-----------------"); Serial.println("-----------------");
Serial.println("JSON-Parsed Data:"); Serial.println("JSON-Parsed Data:");
Serial.println(version);
Serial.println(protocol);
Serial.println(color_hex); Serial.println(color_hex);
Serial.println(type); Serial.println(type);
Serial.println(min_temp); Serial.println(min_temp);
@ -93,8 +89,16 @@ bool formatNdefTag() {
return success; return success;
} }
uint16_t readTagSize()
{
uint8_t buffer[4];
memset(buffer, 0, 4);
nfc.ntag2xx_ReadPage(3, buffer);
return buffer[2]*8;
}
uint8_t ntag2xx_WriteNDEF(const char *payload) { uint8_t ntag2xx_WriteNDEF(const char *payload) {
uint8_t tagSize = 240; // 144 bytes is maximum for NTAG213 uint16_t tagSize = readTagSize();
Serial.print("Tag Size: ");Serial.println(tagSize); Serial.print("Tag Size: ");Serial.println(tagSize);
uint8_t pageBuffer[4] = {0, 0, 0, 0}; uint8_t pageBuffer[4] = {0, 0, 0, 0};
@ -136,6 +140,8 @@ uint8_t ntag2xx_WriteNDEF(const char *payload) {
if (combinedData == NULL) if (combinedData == NULL)
{ {
Serial.println("Fehler: Nicht genug Speicher vorhanden."); Serial.println("Fehler: Nicht genug Speicher vorhanden.");
oledShowMessage("Tag too small");
vTaskDelay(2000 / portTICK_PERIOD_MS);
return 0; return 0;
} }
@ -236,7 +242,7 @@ void writeJsonToTag(void *parameter) {
Serial.println("Erstelle NDEF-Message..."); Serial.println("Erstelle NDEF-Message...");
Serial.println(payload); Serial.println(payload);
hasReadRfidTag = 3; nfcReaderState = NFC_WRITING;
vTaskSuspend(RfidReaderTask); vTaskSuspend(RfidReaderTask);
vTaskDelay(50 / portTICK_PERIOD_MS); vTaskDelay(50 / portTICK_PERIOD_MS);
@ -282,7 +288,7 @@ void writeJsonToTag(void *parameter) {
//oledShowMessage("NFC-Tag written"); //oledShowMessage("NFC-Tag written");
oledShowIcon("success"); oledShowIcon("success");
vTaskDelay(1000 / portTICK_PERIOD_MS); vTaskDelay(1000 / portTICK_PERIOD_MS);
hasReadRfidTag = 5; nfcReaderState = NFC_WRITE_SUCCESS;
// aktualisieren der Website wenn sich der Status ändert // aktualisieren der Website wenn sich der Status ändert
sendNfcData(nullptr); sendNfcData(nullptr);
pauseBambuMqttTask = false; pauseBambuMqttTask = false;
@ -304,7 +310,7 @@ void writeJsonToTag(void *parameter) {
Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag"); Serial.println("Fehler beim Schreiben der NDEF-Message auf den Tag");
oledShowIcon("failed"); oledShowIcon("failed");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
hasReadRfidTag = 4; nfcReaderState = NFC_WRITE_ERROR;
} }
} }
else else
@ -312,7 +318,7 @@ void writeJsonToTag(void *parameter) {
Serial.println("Fehler: Kein Tag zu schreiben gefunden."); Serial.println("Fehler: Kein Tag zu schreiben gefunden.");
oledShowMessage("No NFC-Tag found"); oledShowMessage("No NFC-Tag found");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
hasReadRfidTag = 0; nfcReaderState = NFC_IDLE;
} }
sendWriteResult(nullptr, success); sendWriteResult(nullptr, success);
@ -328,7 +334,7 @@ void startWriteJsonToTag(const char* payload) {
char* payloadCopy = strdup(payload); char* payloadCopy = strdup(payload);
// Task nicht mehrfach starten // Task nicht mehrfach starten
if (hasReadRfidTag != 3) { if (nfcReaderState != NFC_WRITING) {
// Erstelle die Task // Erstelle die Task
xTaskCreate( xTaskCreate(
writeJsonToTag, // Task-Funktion writeJsonToTag, // Task-Funktion
@ -345,7 +351,7 @@ void scanRfidTask(void * parameter) {
Serial.println("RFID Task gestartet"); Serial.println("RFID Task gestartet");
for(;;) { for(;;) {
// Wenn geschrieben wird Schleife aussetzen // Wenn geschrieben wird Schleife aussetzen
if (hasReadRfidTag != 3) if (nfcReaderState != NFC_WRITING)
{ {
yield(); yield();
@ -357,33 +363,31 @@ void scanRfidTask(void * parameter) {
foundNfcTag(nullptr, success); foundNfcTag(nullptr, success);
if (success && hasReadRfidTag != 1) if (success && nfcReaderState != NFC_READ_SUCCESS)
{ {
// Display some basic information about the card // Display some basic information about the card
Serial.println("Found an ISO14443A card"); Serial.println("Found an ISO14443A card");
hasReadRfidTag = 6; nfcReaderState = NFC_READING;
oledShowIcon("transfer"); oledShowIcon("transfer");
vTaskDelay(500 / portTICK_PERIOD_MS); vTaskDelay(500 / portTICK_PERIOD_MS);
if (uidLength == 7) if (uidLength == 7)
{ {
uint8_t data[256]; uint16_t tagSize = readTagSize();
if(tagSize > 0)
{
// Create a buffer depending on the size of the tag
uint8_t* data = (uint8_t*)malloc(tagSize);
memset(data, 0, tagSize);
// We probably have an NTAG2xx card (though it could be Ultralight as well) // We probably have an NTAG2xx card (though it could be Ultralight as well)
Serial.println("Seems to be an NTAG2xx tag (7 byte UID)"); Serial.println("Seems to be an NTAG2xx tag (7 byte UID)");
for (uint8_t i = 0; i < 45; i++) { uint8_t numPages = readTagSize()/4;
/* for (uint8_t i = 4; i < 4+numPages; i++) {
if (i < uidLength) { if (!nfc.ntag2xx_ReadPage(i, data+(i-4) * 4))
uidString += String(uid[i], HEX);
if (i < uidLength - 1) {
uidString += ":"; // Optional: Trennzeichen hinzufügen
}
}
*/
if (!nfc.mifareclassic_ReadDataBlock(i, data + (i - 4) * 4))
{ {
break; // Stop if reading fails break; // Stop if reading fails
} }
@ -402,13 +406,20 @@ void scanRfidTask(void * parameter) {
{ {
oledShowMessage("NFC-Tag unknown"); oledShowMessage("NFC-Tag unknown");
vTaskDelay(2000 / portTICK_PERIOD_MS); vTaskDelay(2000 / portTICK_PERIOD_MS);
hasReadRfidTag = 2; nfcReaderState = NFC_READ_ERROR;
} }
else else
{ {
hasReadRfidTag = 1; nfcReaderState = NFC_READ_SUCCESS;
} }
free(data);
}
else
{
oledShowMessage("NFC-Tag read error");
nfcReaderState = NFC_READ_ERROR;
}
} }
else else
{ {
@ -416,9 +427,9 @@ void scanRfidTask(void * parameter) {
} }
} }
if (!success && hasReadRfidTag > 0) if (!success && nfcReaderState != NFC_IDLE)
{ {
hasReadRfidTag = 0; nfcReaderState = NFC_IDLE;
//uidString = ""; //uidString = "";
nfcJsonData = ""; nfcJsonData = "";
Serial.println("Tag entfernt"); Serial.println("Tag entfernt");

View File

@ -3,6 +3,16 @@
#include <Arduino.h> #include <Arduino.h>
typedef enum{
NFC_IDLE,
NFC_READING,
NFC_READ_SUCCESS,
NFC_READ_ERROR,
NFC_WRITING,
NFC_WRITE_SUCCESS,
NFC_WRITE_ERROR
} nfcReaderStateType;
void startNfc(); void startNfc();
void scanRfidTask(void * parameter); void scanRfidTask(void * parameter);
void startWriteJsonToTag(const char* payload); void startWriteJsonToTag(const char* payload);
@ -10,7 +20,9 @@ void startWriteJsonToTag(const char* payload);
extern TaskHandle_t RfidReaderTask; extern TaskHandle_t RfidReaderTask;
extern String nfcJsonData; extern String nfcJsonData;
extern String spoolId; extern String spoolId;
extern volatile uint8_t hasReadRfidTag; extern volatile nfcReaderStateType nfcReaderState;
extern volatile bool pauseBambuMqttTask; extern volatile bool pauseBambuMqttTask;
#endif #endif

View File

@ -1,6 +1,10 @@
#include <Arduino.h> #include <Arduino.h>
#include <website.h> #include <website.h>
#include <commonFS.h> #include <commonFS.h>
#include "scale.h"
#include "bambu.h"
#include "nfc.h"
// Globale Variablen für Config Backups hinzufügen // Globale Variablen für Config Backups hinzufügen
String bambuCredentialsBackup; String bambuCredentialsBackup;
@ -14,6 +18,34 @@ static size_t updateTotalSize = 0;
static size_t updateWritten = 0; static size_t updateWritten = 0;
static bool isSpiffsUpdate = false; static bool isSpiffsUpdate = false;
/**
* Compares two version strings and determines if version1 is less than version2
*
* @param version1 First version string (format: x.y.z)
* @param version2 Second version string (format: x.y.z)
* @return true if version1 is less than version2
*/
bool isVersionLessThan(const String& version1, const String& version2) {
int major1 = 0, minor1 = 0, patch1 = 0;
int major2 = 0, minor2 = 0, patch2 = 0;
// Parse version1
sscanf(version1.c_str(), "%d.%d.%d", &major1, &minor1, &patch1);
// Parse version2
sscanf(version2.c_str(), "%d.%d.%d", &major2, &minor2, &patch2);
// Compare major version
if (major1 < major2) return true;
if (major1 > major2) return false;
// Major versions equal, compare minor
if (minor1 < minor2) return true;
if (minor1 > minor2) return false;
// Minor versions equal, compare patch
return patch1 < patch2;
}
void backupJsonConfigs() { void backupJsonConfigs() {
// Bambu Credentials backup // Bambu Credentials backup
@ -111,8 +143,37 @@ void handleUpdate(AsyncWebServer &server) {
updateHandler->setUri("/update"); updateHandler->setUri("/update");
updateHandler->setMethod(HTTP_POST); updateHandler->setMethod(HTTP_POST);
// Check if current version is less than defined TOOLVERSION before proceeding with update
if (isVersionLessThan(VERSION, TOOLDVERSION)) {
updateHandler->onRequest([](AsyncWebServerRequest *request) {
request->send(400, "application/json",
"{\"success\":false,\"message\":\"Your current version is too old. Please perform a full upgrade.\"}");
});
server.addHandler(updateHandler);
return;
}
updateHandler->onUpload([](AsyncWebServerRequest *request, String filename, updateHandler->onUpload([](AsyncWebServerRequest *request, String filename,
size_t index, uint8_t *data, size_t len, bool final) { size_t index, uint8_t *data, size_t len, bool final) {
// Disable all Tasks
if (BambuMqttTask != NULL)
{
Serial.println("Delete BambuMqttTask");
vTaskDelete(BambuMqttTask);
BambuMqttTask = NULL;
}
if (ScaleTask) {
Serial.println("Delete ScaleTask");
vTaskDelete(ScaleTask);
ScaleTask = NULL;
}
if (RfidReaderTask) {
Serial.println("Delete RfidReaderTask");
vTaskDelete(RfidReaderTask);
RfidReaderTask = NULL;
}
if (!index) { if (!index) {
updateTotalSize = request->contentLength(); updateTotalSize = request->contentLength();
updateWritten = 0; updateWritten = 0;
@ -121,9 +182,9 @@ void handleUpdate(AsyncWebServer &server) {
if (isSpiffsUpdate) { if (isSpiffsUpdate) {
// Backup vor dem Update // Backup vor dem Update
sendUpdateProgress(0, "backup", "Backing up configurations..."); sendUpdateProgress(0, "backup", "Backing up configurations...");
delay(200); vTaskDelay(200 / portTICK_PERIOD_MS);
backupJsonConfigs(); backupJsonConfigs();
delay(200); vTaskDelay(200 / portTICK_PERIOD_MS);
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL);
if (!partition || !Update.begin(partition->size, U_SPIFFS)) { if (!partition || !Update.begin(partition->size, U_SPIFFS)) {
@ -131,14 +192,14 @@ void handleUpdate(AsyncWebServer &server) {
return; return;
} }
sendUpdateProgress(5, "starting", "Starting SPIFFS update..."); sendUpdateProgress(5, "starting", "Starting SPIFFS update...");
delay(200); vTaskDelay(200 / portTICK_PERIOD_MS);
} else { } else {
if (!Update.begin(updateTotalSize)) { if (!Update.begin(updateTotalSize)) {
request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}"); request->send(400, "application/json", "{\"success\":false,\"message\":\"Update initialization failed\"}");
return; return;
} }
sendUpdateProgress(0, "starting", "Starting firmware update..."); sendUpdateProgress(0, "starting", "Starting firmware update...");
delay(200); vTaskDelay(200 / portTICK_PERIOD_MS);
} }
} }
@ -164,7 +225,7 @@ void handleUpdate(AsyncWebServer &server) {
if (currentProgress != lastProgress && (currentProgress % 10 == 0 || final)) { if (currentProgress != lastProgress && (currentProgress % 10 == 0 || final)) {
sendUpdateProgress(currentProgress, "uploading"); sendUpdateProgress(currentProgress, "uploading");
oledShowMessage("Update: " + String(currentProgress) + "%"); oledShowMessage("Update: " + String(currentProgress) + "%");
delay(50); vTaskDelay(50 / portTICK_PERIOD_MS);
lastProgress = currentProgress; lastProgress = currentProgress;
} }
} }

View File

@ -15,14 +15,30 @@ int16_t weight = 0;
uint8_t weigthCouterToApi = 0; uint8_t weigthCouterToApi = 0;
uint8_t scale_tare_counter = 0; uint8_t scale_tare_counter = 0;
bool scaleTareRequest = false;
uint8_t pauseMainTask = 0; uint8_t pauseMainTask = 0;
uint8_t scaleCalibrated = 1; uint8_t scaleCalibrated = 1;
Preferences preferences; Preferences preferences;
const char* NVS_NAMESPACE = "scale"; const char* NVS_NAMESPACE = "scale";
const char* NVS_KEY_CALIBRATION = "cal_value"; const char* NVS_KEY_CALIBRATION = "cal_value";
const char* NVS_KEY_AUTOTARE = "auto_tare";
bool autoTare = true;
// ##### Funktionen für Waage ##### // ##### Funktionen für Waage #####
uint8_t setAutoTare(bool autoTareValue) {
Serial.print("Set AutoTare to ");
Serial.println(autoTareValue);
autoTare = autoTareValue;
// Speichern mit NVS
preferences.begin(NVS_NAMESPACE, false); // false = readwrite
preferences.putBool(NVS_KEY_AUTOTARE, autoTare);
preferences.end();
return 1;
}
uint8_t tareScale() { uint8_t tareScale() {
Serial.println("Tare scale"); Serial.println("Tare scale");
scale.tare(); scale.tare();
@ -34,30 +50,51 @@ void scale_loop(void * parameter) {
Serial.println("++++++++++++++++++++++++++++++"); Serial.println("++++++++++++++++++++++++++++++");
Serial.println("Scale Loop started"); Serial.println("Scale Loop started");
Serial.println("++++++++++++++++++++++++++++++"); Serial.println("++++++++++++++++++++++++++++++");
for(;;) { for(;;) {
if (scale.is_ready()) if (scale.is_ready())
{ {
// Waage nochmal Taren, wenn zu lange Abweichung // Waage automatisch Taren, wenn zu lange Abweichung
if (scale_tare_counter >= 5) if (autoTare && scale_tare_counter >= 5)
{ {
Serial.println("Auto Tare scale");
scale.tare(); scale.tare();
scale_tare_counter = 0; scale_tare_counter = 0;
} }
// Waage manuell Taren
if (scaleTareRequest == true)
{
Serial.println("Re-Tare scale");
oledShowMessage("TARE Scale");
vTaskDelay(pdMS_TO_TICKS(1000));
scale.tare();
vTaskDelay(pdMS_TO_TICKS(1000));
oledShowWeight(0);
scaleTareRequest = false;
}
weight = round(scale.get_units()); weight = round(scale.get_units());
} }
vTaskDelay(pdMS_TO_TICKS(100)); // Verzögerung, um die CPU nicht zu überlasten vTaskDelay(pdMS_TO_TICKS(100));
} }
} }
uint8_t start_scale() { void start_scale(bool touchSensorConnected) {
Serial.println("Prüfe Calibration Value"); Serial.println("Prüfe Calibration Value");
long calibrationValue; float calibrationValue;
// NVS lesen // NVS lesen
preferences.begin(NVS_NAMESPACE, true); // true = readonly preferences.begin(NVS_NAMESPACE, true); // true = readonly
calibrationValue = preferences.getLong(NVS_KEY_CALIBRATION, defaultScaleCalibrationValue); calibrationValue = preferences.getFloat(NVS_KEY_CALIBRATION, defaultScaleCalibrationValue);
// auto Tare
// Wenn Touch Sensor verbunden, dann autoTare auf false setzen
// Danach prüfen was in NVS gespeichert ist
autoTare = (touchSensorConnected) ? false : true;
autoTare = preferences.getBool(NVS_KEY_AUTOTARE, autoTare);
preferences.end(); preferences.end();
Serial.print("Read Scale Calibration Value "); Serial.print("Read Scale Calibration Value ");
@ -68,6 +105,13 @@ uint8_t start_scale() {
if (isnan(calibrationValue) || calibrationValue < 1) { if (isnan(calibrationValue) || calibrationValue < 1) {
calibrationValue = defaultScaleCalibrationValue; calibrationValue = defaultScaleCalibrationValue;
scaleCalibrated = 0; scaleCalibrated = 0;
oledShowMessage("Scale not calibrated!");
for (uint16_t i = 0; i < 50000; i++) {
yield();
vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset();
}
} }
oledShowMessage("Scale Tare Please remove all"); oledShowMessage("Scale Tare Please remove all");
@ -90,7 +134,7 @@ uint8_t start_scale() {
BaseType_t result = xTaskCreatePinnedToCore( BaseType_t result = xTaskCreatePinnedToCore(
scale_loop, /* Function to implement the task */ scale_loop, /* Function to implement the task */
"ScaleLoop", /* Name of the task */ "ScaleLoop", /* Name of the task */
10000, /* Stack size in words */ 2048, /* Stack size in words */
NULL, /* Task input parameter */ NULL, /* Task input parameter */
scaleTaskPrio, /* Priority of the task */ scaleTaskPrio, /* Priority of the task */
&ScaleTask, /* Task handle. */ &ScaleTask, /* Task handle. */
@ -101,20 +145,21 @@ uint8_t start_scale() {
} else { } else {
Serial.println("ScaleLoop-Task erfolgreich erstellt"); Serial.println("ScaleLoop-Task erfolgreich erstellt");
} }
return (scaleCalibrated == 1) ? 1 : 3;
} }
uint8_t calibrate_scale() { uint8_t calibrate_scale() {
long newCalibrationValue; uint8_t returnState = 0;
float newCalibrationValue;
vTaskSuspend(RfidReaderTask);
vTaskSuspend(ScaleTask);
//vTaskSuspend(RfidReaderTask);
vTaskDelete(RfidReaderTask);
pauseBambuMqttTask = true; pauseBambuMqttTask = true;
pauseMainTask = 1; pauseMainTask = 1;
if (scale.wait_ready_timeout(1000)) if (scale.wait_ready_timeout(1000))
{ {
scale.set_scale(); scale.set_scale();
oledShowMessage("Step 1 empty Scale"); oledShowMessage("Step 1 empty Scale");
@ -136,7 +181,7 @@ uint8_t calibrate_scale() {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
long newCalibrationValue = scale.get_units(10); float newCalibrationValue = scale.get_units(10);
Serial.print("Result: "); Serial.print("Result: ");
Serial.println(newCalibrationValue); Serial.println(newCalibrationValue);
@ -149,28 +194,33 @@ uint8_t calibrate_scale() {
// Speichern mit NVS // Speichern mit NVS
preferences.begin(NVS_NAMESPACE, false); // false = readwrite preferences.begin(NVS_NAMESPACE, false); // false = readwrite
preferences.putLong(NVS_KEY_CALIBRATION, newCalibrationValue); preferences.putFloat(NVS_KEY_CALIBRATION, newCalibrationValue);
preferences.end(); preferences.end();
// Verifizieren // Verifizieren
preferences.begin(NVS_NAMESPACE, true); preferences.begin(NVS_NAMESPACE, true);
long verifyValue = preferences.getLong(NVS_KEY_CALIBRATION, 0); float verifyValue = preferences.getFloat(NVS_KEY_CALIBRATION, 0);
preferences.end(); preferences.end();
Serial.print("Verified stored value: "); Serial.print("Verified stored value: ");
Serial.println(verifyValue); Serial.println(verifyValue);
Serial.println("End calibration, revome weight"); Serial.println("End calibration, remove weight");
oledShowMessage("Remove weight"); oledShowMessage("Remove weight");
scale.set_scale(newCalibrationValue);
for (uint16_t i = 0; i < 2000; i++) { for (uint16_t i = 0; i < 2000; i++) {
yield(); yield();
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
oledShowMessage("Calibration done"); oledShowMessage("Scale calibrated");
// For some reason it is not possible to re-tare the scale here, it will result in a wdt timeout. Instead let the scale loop do the taring
//scale.tare();
scaleTareRequest = true;
for (uint16_t i = 0; i < 2000; i++) { for (uint16_t i = 0; i < 2000; i++) {
yield(); yield();
@ -178,8 +228,9 @@ uint8_t calibrate_scale() {
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
//ESP.restart(); returnState = 1;
} }
else else
{ {
{ {
@ -192,7 +243,7 @@ uint8_t calibrate_scale() {
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
return 0; returnState = 0;
} }
} }
} }
@ -207,17 +258,13 @@ uint8_t calibrate_scale() {
vTaskDelay(pdMS_TO_TICKS(1)); vTaskDelay(pdMS_TO_TICKS(1));
esp_task_wdt_reset(); esp_task_wdt_reset();
} }
return 0; returnState = 0;
} }
oledShowMessage("Scale Ready"); vTaskResume(RfidReaderTask);
vTaskResume(ScaleTask);
Serial.println("starte Scale Task");
start_scale();
pauseBambuMqttTask = false; pauseBambuMqttTask = false;
pauseMainTask = 0; pauseMainTask = 0;
return 1; return returnState;
} }

View File

@ -4,8 +4,8 @@
#include <Arduino.h> #include <Arduino.h>
#include "HX711.h" #include "HX711.h"
uint8_t setAutoTare(bool autoTareValue);
uint8_t start_scale(); uint8_t start_scale(bool touchSensorConnected);
uint8_t calibrate_scale(); uint8_t calibrate_scale();
uint8_t tareScale(); uint8_t tareScale();
@ -13,8 +13,10 @@ extern HX711 scale;
extern int16_t weight; extern int16_t weight;
extern uint8_t weigthCouterToApi; extern uint8_t weigthCouterToApi;
extern uint8_t scale_tare_counter; extern uint8_t scale_tare_counter;
extern uint8_t scaleTareRequest;
extern uint8_t pauseMainTask; extern uint8_t pauseMainTask;
extern uint8_t scaleCalibrated; extern uint8_t scaleCalibrated;
extern bool autoTare;
extern TaskHandle_t ScaleTask; extern TaskHandle_t ScaleTask;

View File

@ -22,14 +22,14 @@ AsyncWebServer server(webserverPort);
AsyncWebSocket ws("/ws"); AsyncWebSocket ws("/ws");
uint8_t lastSuccess = 0; uint8_t lastSuccess = 0;
uint8_t lastHasReadRfidTag = 0; nfcReaderStateType lastnfcReaderState = NFC_IDLE;
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) { if (type == WS_EVT_CONNECT) {
Serial.println("Neuer Client verbunden!"); Serial.println("Neuer Client verbunden!");
// Sende die AMS-Daten an den neuen Client // Sende die AMS-Daten an den neuen Client
sendAmsData(client); if (!bambuDisabled) sendAmsData(client);
sendNfcData(client); sendNfcData(client);
foundNfcTag(client, 0); foundNfcTag(client, 0);
sendWriteResult(client, 3); sendWriteResult(client, 3);
@ -44,13 +44,15 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, message); deserializeJson(doc, message);
bool spoolmanConnected = (spoolmanApiState != API_INIT);
if (doc["type"] == "heartbeat") { if (doc["type"] == "heartbeat") {
// Sende Heartbeat-Antwort // Sende Heartbeat-Antwort
ws.text(client->id(), "{" ws.text(client->id(), "{"
"\"type\":\"heartbeat\"," "\"type\":\"heartbeat\","
"\"freeHeap\":" + String(ESP.getFreeHeap()/1024) + "," "\"freeHeap\":" + String(ESP.getFreeHeap()/1024) + ","
"\"bambu_connected\":" + String(bambu_connected) + "," "\"bambu_connected\":" + String(bambu_connected) + ","
"\"spoolman_connected\":" + String(spoolman_connected) + "" "\"spoolman_connected\":" + String(spoolmanConnected) + ""
"}"); "}");
} }
@ -73,6 +75,10 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
success = calibrate_scale(); success = calibrate_scale();
} }
if (doc["payload"] == "setAutoTare") {
success = setAutoTare(doc["enabled"].as<bool>());
}
if (success) { if (success) {
ws.textAll("{\"type\":\"scale\",\"payload\":\"success\"}"); ws.textAll("{\"type\":\"scale\",\"payload\":\"success\"}");
} else { } else {
@ -139,34 +145,31 @@ void foundNfcTag(AsyncWebSocketClient *client, uint8_t success) {
} }
void sendNfcData(AsyncWebSocketClient *client) { void sendNfcData(AsyncWebSocketClient *client) {
if (lastHasReadRfidTag == hasReadRfidTag) return; if (lastnfcReaderState == nfcReaderState) return;
if (hasReadRfidTag == 0) { // TBD: Why is there no status for reading the tag?
switch(nfcReaderState){
case NFC_IDLE:
ws.textAll("{\"type\":\"nfcData\", \"payload\":{}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{}}");
} break;
else if (hasReadRfidTag == 1) { case NFC_READ_SUCCESS:
ws.textAll("{\"type\":\"nfcData\", \"payload\":" + nfcJsonData + "}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":" + nfcJsonData + "}");
} break;
else if (hasReadRfidTag == 2) case NFC_READ_ERROR:
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Empty Tag or Data not readable\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Empty Tag or Data not readable\"}}");
} break;
else if (hasReadRfidTag == 3) case NFC_WRITING:
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Schreibe Tag...\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Schreibe Tag...\"}}");
} break;
else if (hasReadRfidTag == 4) case NFC_WRITE_SUCCESS:
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Error writing to Tag\"}}");
}
else if (hasReadRfidTag == 5)
{
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Tag erfolgreich geschrieben\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"info\":\"Tag erfolgreich geschrieben\"}}");
} break;
else case NFC_WRITE_ERROR:
{ ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Error writing to Tag\"}}");
break;
case DEFAULT:
ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Something went wrong\"}}"); ws.textAll("{\"type\":\"nfcData\", \"payload\":{\"error\":\"Something went wrong\"}}");
} }
lastHasReadRfidTag = hasReadRfidTag; lastnfcReaderState = nfcReaderState;
} }
void sendAmsData(AsyncWebSocketClient *client) { void sendAmsData(AsyncWebSocketClient *client) {
@ -204,16 +207,23 @@ void setupWebserver(AsyncWebServer &server) {
// Route für Waage // Route für Waage
server.on("/waage", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/waage", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Anfrage für /waage erhalten"); Serial.println("Anfrage für /waage erhalten");
AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/waage.html.gz", "text/html"); //AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/waage.html.gz", "text/html");
response->addHeader("Content-Encoding", "gzip"); //response->addHeader("Content-Encoding", "gzip");
response->addHeader("Cache-Control", CACHE_CONTROL); //response->addHeader("Cache-Control", CACHE_CONTROL);
request->send(response);
String html = loadHtmlWithHeader("/waage.html");
html.replace("{{autoTare}}", (autoTare) ? "checked" : "");
request->send(200, "text/html", html);
}); });
// Route für RFID // Route für RFID
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Anfrage für /rfid erhalten"); Serial.println("Anfrage für /rfid erhalten");
AsyncWebServerResponse *response = request->beginResponse(LittleFS, "/rfid.html.gz", "text/html");
String page = (bambuDisabled) ? "/rfid.html.gz" : "/rfid_bambu.html.gz";
AsyncWebServerResponse *response = request->beginResponse(LittleFS, page, "text/html");
response->addHeader("Content-Encoding", "gzip"); response->addHeader("Content-Encoding", "gzip");
response->addHeader("Cache-Control", CACHE_CONTROL); response->addHeader("Cache-Control", CACHE_CONTROL);
request->send(response); request->send(response);
@ -239,7 +249,10 @@ void setupWebserver(AsyncWebServer &server) {
server.on("/spoolman", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/spoolman", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Anfrage für /spoolman erhalten"); Serial.println("Anfrage für /spoolman erhalten");
String html = loadHtmlWithHeader("/spoolman.html"); String html = loadHtmlWithHeader("/spoolman.html");
html.replace("{{spoolmanUrl}}", spoolmanUrl); html.replace("{{spoolmanUrl}}", (spoolmanUrl != "") ? spoolmanUrl : "");
html.replace("{{spoolmanOctoEnabled}}", octoEnabled ? "checked" : "");
html.replace("{{spoolmanOctoUrl}}", (octoUrl != "") ? octoUrl : "");
html.replace("{{spoolmanOctoToken}}", (octoToken != "") ? octoToken : "");
JsonDocument doc; JsonDocument doc;
if (loadJsonValue("/bambu_credentials.json", doc) && doc["bambu_ip"].is<String>()) if (loadJsonValue("/bambu_credentials.json", doc) && doc["bambu_ip"].is<String>())
@ -277,17 +290,45 @@ void setupWebserver(AsyncWebServer &server) {
return; return;
} }
String url = request->getParam("url")->value(); if (request->getParam("octoEnabled")->value() == "true" && (!request->hasParam("octoUrl") || !request->hasParam("octoToken"))) {
url.trim(); request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing OctoPrint URL or Token parameter\"}");
return;
}
bool healthy = saveSpoolmanUrl(url); String url = request->getParam("url")->value();
if (url.indexOf("http://") == -1 && url.indexOf("https://") == -1) {
url = "http://" + url;
}
// Remove trailing slash if exists
if (url.length() > 0 && url.charAt(url.length()-1) == '/') {
url = url.substring(0, url.length()-1);
}
bool octoEnabled = (request->getParam("octoEnabled")->value() == "true") ? true : false;
String octoUrl = request->getParam("octoUrl")->value();
String octoToken = (request->getParam("octoToken")->value() != "") ? request->getParam("octoToken")->value() : "";
url.trim();
octoUrl.trim();
octoToken.trim();
bool healthy = saveSpoolmanUrl(url, octoEnabled, octoUrl, octoToken);
String jsonResponse = "{\"healthy\": " + String(healthy ? "true" : "false") + "}"; String jsonResponse = "{\"healthy\": " + String(healthy ? "true" : "false") + "}";
request->send(200, "application/json", jsonResponse); request->send(200, "application/json", jsonResponse);
}); });
// Route für das Überprüfen der Spoolman-Instanz // Route für das Überprüfen der Bambu-Instanz
server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request){ server.on("/api/bambu", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("remove")) {
if (removeBambuCredentials()) {
request->send(200, "application/json", "{\"success\": true}");
} else {
request->send(500, "application/json", "{\"success\": false, \"error\": \"Fehler beim Löschen der Bambu-Credentials\"}");
}
return;
}
if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) { if (!request->hasParam("bambu_ip") || !request->hasParam("bambu_serialnr") || !request->hasParam("bambu_accesscode")) {
request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}"); request->send(400, "application/json", "{\"success\": false, \"error\": \"Missing parameter\"}");
return; return;

View File

@ -59,7 +59,7 @@ void initWiFi() {
if(wm_nonblocking) wm.setConfigPortalBlocking(false); if(wm_nonblocking) wm.setConfigPortalBlocking(false);
//wm.setConfigPortalTimeout(320); // Portal nach 5min schließen //wm.setConfigPortalTimeout(320); // Portal nach 5min schließen
wm.setWiFiAutoReconnect(true); wm.setWiFiAutoReconnect(true);
wm.setConnectTimeout(5); wm.setConnectTimeout(10);
oledShowTopRow(); oledShowTopRow();
oledShowMessage("WiFi Setup"); oledShowMessage("WiFi Setup");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

View File

@ -0,0 +1,12 @@
## **Heat insert location**
Housing:
- every hole is made to fit a heat insert
![](./Housing_Heatinsert_Location_usermod_spitzbirne32_.png)
---
Scale top:
- two heat inserts for the NFC Reader
![](./ScaleTop_Heatinsert_Location_usermod_spitzbirne32_.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -0,0 +1,69 @@
## Modifications
To reduce costs, components were sourced from AliExpress instead of Amazon. However, differences in dimensions and mounting hole spacing necessitated adjustments to the 3D-printed parts. Additionally M3 heat inserts were used to limit M4 screws to a minimum.
![](./Images/Showcase_usermod_spitzbirne32.gif)
---
List of parts that were used:
- Display: https://aliexpress.com/item/1005007389730469.html
- Scale(5KG with HX711): https://aliexpress.com/item/1005006827930173.html
- NFC Reader: https://aliexpress.com/item/1005005973913526.html
- NFC Chips: https://aliexpress.com/item/1005006332360160.html
- [VORON](https://vorondesign.com/) Heat Inserts M3 OD5mm L4mm: https://aliexpress.com/item/1005003582355741.html - make sure to select the correct size
---
- **Parts are designed to be printed in ABS/ASA.** Shrinking compensation not needed.
- **Display and Scale Adjustments:** The AliExpress-sourced display and scale had different dimensions and hole spacings compared to the Amazon versions. The 3D models were modified to accommodate these differences, ensuring proper fit and functionality.
- measurement of my Display & Scale to check if your parts will fit can be found in the images folder
- **Screw Size and Heat Inserts:** All holes originally designed for M4 screws were resized to fit M3 screws. Standard VORON heat inserts were incorporated to provide durable threading. This change standardizes the hardware and simplifies assembly.
- **Display Mounting:** The display is now mounted using M3 screws with VORON heat inserts. The display's mounting holes need to be drilled to 3mm to accommodate the M3 screws.
- **Scale Top Surface:** The top surface of the scale was modified to allow M3 socket head cap screws to sit flush with the 3D-printed part. This design ensures that the filament spool rests flat without interference.
- **NFC Reader Mounting:** The NFC reader is also secured using M3 screws and VORON heat inserts, maintaining consistency across all components.
- **Scale Base Mounting:** The only M4 screws required are for attaching the metal part of the scale to its base.
## Benefits of Modifications
- **Cost Reduction:** Sourcing components from AliExpress offers a more affordable alternative to Amazon, making the project more accessible.
- **Standardized Hardware:** Using M3 screws and [VORON](https://vorondesign.com/) heat inserts throughout the assembly simplifies the build process and reduces the variety of required hardware.
- **Enhanced Compatibility:** Adjustments to the 3D models ensure compatibility with readily available components, accommodating variations in part dimensions.
## Assembly Instructions
1. **Component Preparation:**
- Carefully drill the display's mounting holes to 3mm to fit M3 screws.
2. **Heat Insert Installation:**
- install VORON M3 heat inserts into the designated holes in the 3D-printed housing/case for the ESP32 and Scale top &#8594; [heat insert location pictures](./Images/README.md)
3. **Component Mounting:**
- Attach the display, scale, and NFC reader to their respective mounts using M3 screws.
- Secure the metal part of the scale to its base using M4 screws.
4. **Final Assembly:**
- Assemble all components according to the original FilaMan instructions, ensuring that all modified parts fit correctly and function as intended.
For detailed assembly guides and additional resources, refer to the [original FilaMan documentation](https://github.com/ManuelW77/Filaman).
## Conclusion
These modifications to the FilaMan project provide a cost-effective and standardized approach to building a filament management system. By sourcing components from AliExpress and adjusting the 3D models accordingly, users can achieve the same functionality at a reduced cost, with the added benefit of using uniform hardware throughout the assembly.
## Changelog
### Version 1.0 - 2025-03-04
- Initial release of modifications for AliExpress-sourced components.
- Adjusted 3D models to fit different display and scale dimensions.
- Replaced M4 screws with M3 screws and integrated VORON heat inserts.
- Modified display mounting, requiring drilling to 3mm for M3 screws.
- Adjusted scale top surface for flush screw placement.
- Standardized NFC reader mounting with M3 screws and VORON heat inserts.
- Retained M4 screws only for metal scale attachment.

Binary file not shown.