Compare commits

...

313 commits

Author SHA1 Message Date
GitHub Actions Bot
aacfeb9911 Auto-update Wippersnapper definitions [skip ci] 2025-08-29 00:19:42 +00:00
GitHub Actions Bot
c9dd1a2902 Auto-update Wippersnapper definitions [skip ci] 2025-08-28 00:19:33 +00:00
GitHub Actions Bot
df2cb16499 Auto-update Wippersnapper definitions [skip ci] 2025-08-27 00:19:46 +00:00
GitHub Actions Bot
f98a5429e3 Auto-update Wippersnapper definitions [skip ci] 2025-08-26 00:19:57 +00:00
GitHub Actions Bot
a0eb1a6833 Auto-update Wippersnapper definitions [skip ci] 2025-08-25 00:20:45 +00:00
GitHub Actions Bot
d38264a533 Auto-update Wippersnapper definitions [skip ci] 2025-08-24 00:22:01 +00:00
GitHub Actions Bot
c320cf79b1 Auto-update Wippersnapper definitions [skip ci] 2025-08-23 00:19:09 +00:00
GitHub Actions Bot
38dab380be Auto-update Wippersnapper definitions [skip ci] 2025-08-22 00:19:49 +00:00
GitHub Actions Bot
6f9633db41 Auto-update Wippersnapper definitions [skip ci] 2025-08-21 00:18:56 +00:00
GitHub Actions Bot
8fa835a11b Auto-update Wippersnapper definitions [skip ci] 2025-08-20 00:19:24 +00:00
GitHub Actions Bot
aafc9aeb59 Auto-update Wippersnapper definitions [skip ci] 2025-08-19 00:20:31 +00:00
GitHub Actions Bot
37a7a0a668 Auto-update Wippersnapper definitions [skip ci] 2025-08-18 16:35:13 +00:00
GitHub Actions Bot
b70abd72ea Update submodules to latest versions [skip ci] 2025-08-18 16:34:24 +00:00
Tyeth Gundry
94847e7792
Merge pull request #29 from adafruit/fix-i2c-gps-ingestion
Fix i2c gps ingestion
2025-08-18 17:33:34 +01:00
Tyeth Gundry
053e675503 fix(gps): ensure I2C GPS subproperties are output 2025-08-18 16:27:26 +01:00
Tyeth Gundry
ff9790297e Also set second period field 2025-08-18 16:17:29 +01:00
Tyeth Gundry
6dcfecc8cb Update to latest assets 2025-08-18 16:11:59 +01:00
Tyeth Gundry
129875768f Update boards submodule ref - restore offline boards 2025-08-18 16:10:40 +01:00
Tyeth Gundry
04918f1d11 fix(gps): I2C gps sub-properties set before parent creation 2025-08-18 16:09:27 +01:00
GitHub Actions Bot
9fa0d9c025 Auto-update Wippersnapper definitions [skip ci] 2025-08-18 00:22:28 +00:00
GitHub Actions Bot
0b0b767d6c Auto-update Wippersnapper definitions [skip ci] 2025-08-17 00:22:29 +00:00
GitHub Actions Bot
b2d32ea9a7 Auto-update Wippersnapper definitions [skip ci] 2025-08-16 00:20:08 +00:00
GitHub Actions Bot
8b8aa8efd0 Auto-update Wippersnapper definitions [skip ci] 2025-08-15 16:00:41 +00:00
Tyeth Gundry
0158a39fc6
Merge pull request #6 from adafruit/xiao-breakout
Update boards, CI methods, Add Xiao breakout/camera SD defs
2025-08-15 16:58:59 +01:00
Tyeth Gundry
5923445413 Update assets 2025-08-15 16:55:28 +01:00
Tyeth Gundry
a5f81a5053 Add auto config false at device config level + PCF8563 2025-08-15 16:52:33 +01:00
Tyeth Gundry
8b0068859b Fix unselecting SD CS pin 2025-08-15 16:52:33 +01:00
Tyeth Gundry
f44d1ab582 Remove TODOs 2025-08-15 16:52:33 +01:00
Tyeth Gundry
3a4fd3e8df Rebuild assets 2025-08-15 16:52:33 +01:00
Tyeth Gundry
6ef92f1809 Fix conversion script for degree symbol etc 2025-08-15 16:52:32 +01:00
Tyeth Gundry
4ace2bc551 Rebuild latest assets 2025-08-15 16:52:32 +01:00
Tyeth Gundry
f2f36f039d Improve log message if companion SD CS mismatch 2025-08-15 16:51:10 +01:00
Tyeth Gundry
74074b1973 Add XIAO camera/SD addon board to index.html 2025-08-15 16:51:10 +01:00
Tyeth Gundry
8f3a6df7be Update definition for S3sense camera addon board 2025-08-15 16:51:10 +01:00
Tyeth Gundry
9b02dc97b8 Switch components repo to offline-mode branch 2025-08-15 16:51:10 +01:00
Tyeth Gundry
3dd3c637a7 Switch boards repo to offline-mode branch 2025-08-15 16:40:17 +01:00
Tyeth Gundry
8467d92062 Update nightly CI to offline-mode branches 2025-08-15 16:40:17 +01:00
Tyeth Gundry
036492889e offline-mode branch for board/component urls 2025-08-15 16:40:17 +01:00
Tyeth Gundry
38a1794a32 Mention features for companion board 2025-08-15 16:40:17 +01:00
Tyeth Gundry
1c8273c1ba Update html for new companion board 2025-08-15 16:40:16 +01:00
Tyeth Gundry
684427ae77 Add Expansion Board Base for XIAO 2025-08-15 16:40:16 +01:00
tyeth
08a4e9b2b2 Mention GPS custom datatype/sensortype insertion points 2025-08-15 16:40:16 +01:00
tyeth
189b306683 Update for web-native-usb (not just uf2) 2025-08-15 16:40:16 +01:00
GitHub Actions Bot
f67593fc9f Auto-update Wippersnapper definitions [skip ci] 2025-08-15 00:21:21 +00:00
GitHub Actions Bot
c42f98f149 Auto-update Wippersnapper definitions [skip ci] 2025-08-14 00:20:46 +00:00
GitHub Actions Bot
1f78bc096c Update submodules to latest versions [skip ci] 2025-08-14 00:20:31 +00:00
GitHub Actions Bot
44e42807f5 Auto-update Wippersnapper definitions [skip ci] 2025-08-13 00:20:46 +00:00
GitHub Actions Bot
07039fdd66 Auto-update Wippersnapper definitions [skip ci] 2025-08-12 00:20:49 +00:00
GitHub Actions Bot
869ba82b9a Auto-update Wippersnapper definitions [skip ci] 2025-08-11 00:22:56 +00:00
GitHub Actions Bot
bcb8b4e4ca Auto-update Wippersnapper definitions [skip ci] 2025-08-10 00:23:47 +00:00
GitHub Actions Bot
3ef787e79e Auto-update Wippersnapper definitions [skip ci] 2025-08-09 00:20:08 +00:00
GitHub Actions Bot
3e41dc1bd4 Auto-update Wippersnapper definitions [skip ci] 2025-08-08 00:21:54 +00:00
GitHub Actions Bot
835a05c769 Update submodules to latest versions [skip ci] 2025-08-08 00:21:37 +00:00
Tyeth Gundry
eb673ca465
Merge pull request #5 from adafruit/track-uart-changes
Add GPS and UART Components
2025-08-07 18:17:46 +01:00
brentru
d33fb423bd Refactor for @tyeth 2025-08-07 12:18:43 -04:00
GitHub Actions Bot
935de10302 Auto-update Wippersnapper definitions [skip ci] 2025-08-07 00:22:09 +00:00
brentru
1e65b05eb3 Merge branch 'track-uart-changes' of github.com:adafruit/Adafruit_Wippersnapper_Offline_Configurator into track-uart-changes 2025-08-06 15:12:25 -04:00
brentru
ca2412d5a7 Fix devicetype, sensorType, period 2025-08-06 15:10:41 -04:00
brentru
07daf2ba6b Fix *1000.0 bug 2025-08-06 14:53:26 -04:00
brentru
d8bea463ab use gps/generic_input/pm25aqi set to remove double period fields 2025-08-06 11:02:17 -04:00
brentru
fc160d0ec5 Put back multiplexer code, check for isGps, add isGps period 2025-08-06 10:54:13 -04:00
GitHub Actions Bot
12c5d5f686 Auto-update Wippersnapper definitions [skip ci] 2025-08-06 00:23:10 +00:00
Brent Rubell
e97ff1003f
Merge branch 'main' into track-uart-changes 2025-08-05 16:55:59 -04:00
brentru
b40ab1405a add wippersnapper-config-builder.js isgps 2025-08-05 16:55:09 -04:00
brentru
9dd14ab71c Merge branch 'track-uart-changes' of github.com:adafruit/Adafruit_Wippersnapper_Offline_Configurator into track-uart-changes 2025-08-05 16:54:19 -04:00
brentru
7bde129844 Update config generator and converter to track deviceType change for UART 2025-08-05 16:52:36 -04:00
GitHub Actions Bot
8996ab0661 Auto-update Wippersnapper definitions [skip ci] 2025-08-05 00:22:32 +00:00
GitHub Actions Bot
02cc369eb0 Auto-update Wippersnapper definitions [skip ci] 2025-08-04 00:23:55 +00:00
GitHub Actions Bot
daa4ec8503 Auto-update Wippersnapper definitions [skip ci] 2025-08-03 00:24:30 +00:00
GitHub Actions Bot
b34994845b Auto-update Wippersnapper definitions [skip ci] 2025-08-02 00:21:02 +00:00
Brent Rubell
e3dd1baf5c
Merge branch 'main' into track-uart-changes 2025-08-01 15:16:50 -04:00
brentru
fcf757c9b9 Put back boards.js/json and components.js/json 2025-08-01 15:15:07 -04:00
brentru
24f117a110 Restore submodules and fix .gitignore 2025-08-01 15:13:10 -04:00
brentru
b874489933 Add support for GPS over I2C 2025-08-01 09:57:15 -04:00
brentru
3032861ab1 Add UART GPS 2025-08-01 09:26:15 -04:00
GitHub Actions Bot
33a94b2075 Auto-update Wippersnapper definitions [skip ci] 2025-08-01 00:24:41 +00:00
brentru
e6a8a16db4 Update tool for generic input too 2025-07-31 16:22:20 -04:00
brentru
b442fc7bb8 Update for is_pm1006 2025-07-31 15:02:55 -04:00
brentru
c6028d6788 Stop tracking generated files and submodules - now in .gitignore 2025-07-31 14:27:05 -04:00
brentru
e268e11d35 Update Python script for components, update index 2025-07-31 14:25:15 -04:00
brentru
9bc8652835 Update Wippersnapper_Components to track offline-mode branch 2025-07-31 13:28:20 -04:00
GitHub Actions Bot
9207e9ea53 Auto-update Wippersnapper definitions [skip ci] 2025-07-31 00:23:14 +00:00
GitHub Actions Bot
042a5c8eb9 Auto-update Wippersnapper definitions [skip ci] 2025-07-30 00:22:35 +00:00
GitHub Actions Bot
84bc331930 Auto-update Wippersnapper definitions [skip ci] 2025-07-29 00:23:42 +00:00
GitHub Actions Bot
6f24c55f21 Auto-update Wippersnapper definitions [skip ci] 2025-07-28 00:23:15 +00:00
GitHub Actions Bot
c73cbe4244 Auto-update Wippersnapper definitions [skip ci] 2025-07-27 00:24:04 +00:00
GitHub Actions Bot
cb547052cf Auto-update Wippersnapper definitions [skip ci] 2025-07-26 00:20:51 +00:00
GitHub Actions Bot
ffd58c9354 Auto-update Wippersnapper definitions [skip ci] 2025-07-25 00:21:48 +00:00
GitHub Actions Bot
0d2d66868b Auto-update Wippersnapper definitions [skip ci] 2025-07-24 00:21:39 +00:00
GitHub Actions Bot
2113f0be13 Auto-update Wippersnapper definitions [skip ci] 2025-07-23 00:21:33 +00:00
GitHub Actions Bot
a86aff5e4a Auto-update Wippersnapper definitions [skip ci] 2025-07-21 00:23:20 +00:00
GitHub Actions Bot
a6e0396065 Auto-update Wippersnapper definitions [skip ci] 2025-07-20 00:23:59 +00:00
GitHub Actions Bot
1484cdc272 Auto-update Wippersnapper definitions [skip ci] 2025-07-19 00:20:56 +00:00
GitHub Actions Bot
452ceb2cc2 Auto-update Wippersnapper definitions [skip ci] 2025-07-17 00:26:08 +00:00
GitHub Actions Bot
0d8ada2c8f Auto-update Wippersnapper definitions [skip ci] 2025-07-16 00:21:20 +00:00
GitHub Actions Bot
d6db3be31f Auto-update Wippersnapper definitions [skip ci] 2025-07-14 00:22:36 +00:00
GitHub Actions Bot
156a8874a6 Auto-update Wippersnapper definitions [skip ci] 2025-07-13 00:23:30 +00:00
GitHub Actions Bot
efddc88fba Update submodules to latest versions [skip ci] 2025-07-13 00:23:15 +00:00
GitHub Actions Bot
12d885ef88 Auto-update Wippersnapper definitions [skip ci] 2025-07-12 00:20:11 +00:00
GitHub Actions Bot
e94960708b Update submodules to latest versions [skip ci] 2025-07-12 00:19:59 +00:00
GitHub Actions Bot
f44f1399f2 Auto-update Wippersnapper definitions [skip ci] 2025-07-11 00:20:55 +00:00
GitHub Actions Bot
fb96006700 Auto-update Wippersnapper definitions [skip ci] 2025-07-10 17:46:33 +00:00
GitHub Actions Bot
7237adef36 Update submodules to latest versions [skip ci] 2025-07-10 17:46:16 +00:00
GitHub Actions Bot
ec40ec204c Auto-update Wippersnapper definitions [skip ci] 2025-07-10 00:20:55 +00:00
GitHub Actions Bot
50b92e2fa9 Auto-update Wippersnapper definitions [skip ci] 2025-07-09 00:21:07 +00:00
GitHub Actions Bot
14de6bb28a Auto-update Wippersnapper definitions [skip ci] 2025-07-08 00:20:29 +00:00
GitHub Actions Bot
e81647dc92 Update submodules to latest versions [skip ci] 2025-07-08 00:20:18 +00:00
GitHub Actions Bot
5622d26234 Auto-update Wippersnapper definitions [skip ci] 2025-07-07 00:22:13 +00:00
GitHub Actions Bot
4ad941abc0 Auto-update Wippersnapper definitions [skip ci] 2025-07-06 00:22:45 +00:00
GitHub Actions Bot
98882dfc12 Auto-update Wippersnapper definitions [skip ci] 2025-07-05 00:19:23 +00:00
GitHub Actions Bot
e5d2c5b741 Auto-update Wippersnapper definitions [skip ci] 2025-07-04 00:20:21 +00:00
GitHub Actions Bot
8a143dc843 Auto-update Wippersnapper definitions [skip ci] 2025-07-03 00:20:54 +00:00
GitHub Actions Bot
7dd87f9375 Update submodules to latest versions [skip ci] 2025-07-03 00:20:36 +00:00
GitHub Actions Bot
e4369c12ab Auto-update Wippersnapper definitions [skip ci] 2025-07-02 00:20:24 +00:00
GitHub Actions Bot
b219e9ce52 Auto-update Wippersnapper definitions [skip ci] 2025-07-01 00:23:35 +00:00
GitHub Actions Bot
3098b7bbea Auto-update Wippersnapper definitions [skip ci] 2025-06-30 00:21:49 +00:00
GitHub Actions Bot
1a7afb7123 Auto-update Wippersnapper definitions [skip ci] 2025-06-29 00:23:18 +00:00
GitHub Actions Bot
5fcb3d0632 Auto-update Wippersnapper definitions [skip ci] 2025-06-28 00:19:47 +00:00
GitHub Actions Bot
02b0047c3d Auto-update Wippersnapper definitions [skip ci] 2025-06-27 00:20:51 +00:00
GitHub Actions Bot
433e5c0c56 Auto-update Wippersnapper definitions [skip ci] 2025-06-26 00:20:18 +00:00
GitHub Actions Bot
9b61f68fba Auto-update Wippersnapper definitions [skip ci] 2025-06-25 00:20:42 +00:00
GitHub Actions Bot
7bd3d8569a Auto-update Wippersnapper definitions [skip ci] 2025-06-24 00:20:28 +00:00
GitHub Actions Bot
de0ad47791 Auto-update Wippersnapper definitions [skip ci] 2025-06-23 00:21:53 +00:00
GitHub Actions Bot
f3746bd9ef Auto-update Wippersnapper definitions [skip ci] 2025-06-22 00:27:51 +00:00
GitHub Actions Bot
f1b2b307ca Auto-update Wippersnapper definitions [skip ci] 2025-06-21 00:20:25 +00:00
GitHub Actions Bot
0fa0f41816 Auto-update Wippersnapper definitions [skip ci] 2025-06-20 00:20:16 +00:00
GitHub Actions Bot
b759bd61ac Auto-update Wippersnapper definitions [skip ci] 2025-06-19 00:20:36 +00:00
GitHub Actions Bot
ecd234c700 Update submodules to latest versions [skip ci] 2025-06-19 00:20:19 +00:00
GitHub Actions Bot
5e64255ffa Auto-update Wippersnapper definitions [skip ci] 2025-06-18 00:20:19 +00:00
GitHub Actions Bot
1b63e31296 Auto-update Wippersnapper definitions [skip ci] 2025-06-17 00:20:19 +00:00
GitHub Actions Bot
e045fffe61 Auto-update Wippersnapper definitions [skip ci] 2025-06-16 00:21:49 +00:00
GitHub Actions Bot
af6267bc11 Auto-update Wippersnapper definitions [skip ci] 2025-06-15 00:22:42 +00:00
GitHub Actions Bot
0183ddfbbe Auto-update Wippersnapper definitions [skip ci] 2025-06-14 00:19:38 +00:00
GitHub Actions Bot
4c227a64e7 Auto-update Wippersnapper definitions [skip ci] 2025-06-13 00:20:30 +00:00
GitHub Actions Bot
bdbbf8183a Auto-update Wippersnapper definitions [skip ci] 2025-06-12 00:19:59 +00:00
GitHub Actions Bot
2e4e52213d Auto-update Wippersnapper definitions [skip ci] 2025-06-11 00:20:16 +00:00
GitHub Actions Bot
228f53d64f Auto-update Wippersnapper definitions [skip ci] 2025-06-10 00:20:26 +00:00
GitHub Actions Bot
518be8e77a Auto-update Wippersnapper definitions [skip ci] 2025-06-09 00:21:46 +00:00
GitHub Actions Bot
3837ae8f6d Auto-update Wippersnapper definitions [skip ci] 2025-06-08 00:22:28 +00:00
GitHub Actions Bot
d5de3ec831 Auto-update Wippersnapper definitions [skip ci] 2025-06-07 00:19:57 +00:00
GitHub Actions Bot
53c3718827 Update submodules to latest versions [skip ci] 2025-06-07 00:19:44 +00:00
GitHub Actions Bot
6cebbcbfe3 Auto-update Wippersnapper definitions [skip ci] 2025-06-06 00:20:05 +00:00
GitHub Actions Bot
4f7d684ad0 Auto-update Wippersnapper definitions [skip ci] 2025-06-05 00:20:08 +00:00
GitHub Actions Bot
58ce35381b Auto-update Wippersnapper definitions [skip ci] 2025-06-04 00:20:18 +00:00
GitHub Actions Bot
51cb68e07b Auto-update Wippersnapper definitions [skip ci] 2025-06-03 00:20:39 +00:00
GitHub Actions Bot
6902e98d7b Auto-update Wippersnapper definitions [skip ci] 2025-06-02 00:21:07 +00:00
GitHub Actions Bot
4ea19f134e Auto-update Wippersnapper definitions [skip ci] 2025-06-01 00:29:11 +00:00
GitHub Actions Bot
d9b1d05e4d Auto-update Wippersnapper definitions [skip ci] 2025-05-31 00:19:20 +00:00
GitHub Actions Bot
749c5ebce4 Auto-update Wippersnapper definitions [skip ci] 2025-05-30 00:20:04 +00:00
GitHub Actions Bot
2d0122bebb Auto-update Wippersnapper definitions [skip ci] 2025-05-29 00:21:59 +00:00
GitHub Actions Bot
18fb29eca3 Auto-update Wippersnapper definitions [skip ci] 2025-05-28 00:20:16 +00:00
GitHub Actions Bot
6bc2fb421f Auto-update Wippersnapper definitions [skip ci] 2025-05-27 00:19:31 +00:00
GitHub Actions Bot
72ea8bd966 Auto-update Wippersnapper definitions [skip ci] 2025-05-26 00:20:30 +00:00
GitHub Actions Bot
7158b56fbb Auto-update Wippersnapper definitions [skip ci] 2025-05-25 00:22:19 +00:00
GitHub Actions Bot
ac1b004d12 Auto-update Wippersnapper definitions [skip ci] 2025-05-24 00:19:09 +00:00
GitHub Actions Bot
22664089df Auto-update Wippersnapper definitions [skip ci] 2025-05-23 00:19:52 +00:00
GitHub Actions Bot
683fe9941f Auto-update Wippersnapper definitions [skip ci] 2025-05-22 00:19:39 +00:00
GitHub Actions Bot
7ea402d237 Auto-update Wippersnapper definitions [skip ci] 2025-05-21 00:20:15 +00:00
GitHub Actions Bot
d6a7eb424d Auto-update Wippersnapper definitions [skip ci] 2025-05-20 00:20:30 +00:00
GitHub Actions Bot
c3eb493628 Auto-update Wippersnapper definitions [skip ci] 2025-05-19 00:21:26 +00:00
GitHub Actions Bot
1804a75a88 Auto-update Wippersnapper definitions [skip ci] 2025-05-18 00:21:33 +00:00
GitHub Actions Bot
cd4fb4a704 Auto-update Wippersnapper definitions [skip ci] 2025-05-17 00:19:13 +00:00
GitHub Actions Bot
4fa03081a7 Auto-update Wippersnapper definitions [skip ci] 2025-05-16 00:20:13 +00:00
GitHub Actions Bot
c89d912086 Auto-update Wippersnapper definitions [skip ci] 2025-05-15 00:18:23 +00:00
GitHub Actions Bot
d551c26413 Auto-update Wippersnapper definitions [skip ci] 2025-05-14 23:30:41 +00:00
GitHub Actions Bot
9cbb0a84af Update submodules to latest versions [skip ci] 2025-05-14 23:30:34 +00:00
GitHub Actions Bot
31967fd2c7 Auto-update Wippersnapper definitions [skip ci] 2025-05-14 19:59:51 +00:00
GitHub Actions Bot
aa742d035a Auto-update Wippersnapper definitions [skip ci] 2025-05-14 00:19:55 +00:00
Tyeth Gundry
e01e54a6cd
Update README.md 2025-05-13 22:04:33 +01:00
Tyeth Gundry
4f55fa436d
Update index.html - Select typo 2025-05-13 22:02:13 +01:00
GitHub Actions Bot
338d810cc2 Auto-update Wippersnapper definitions [skip ci] 2025-05-13 17:36:34 +00:00
GitHub Actions Bot
f55eaeffb8 Auto-update Wippersnapper definitions [skip ci] 2025-05-13 12:53:57 +00:00
tyeth
e88aeb8e5d Correct PiCowbell Adalogger companion SD CS Pin 2025-05-13 13:27:54 +01:00
GitHub Actions Bot
73780bf899 Auto-update Wippersnapper definitions [skip ci] 2025-05-13 00:20:14 +00:00
Tyeth Gundry
a69caa87e0
Correct autoConfig to use string encapsulation for bools 2025-05-12 14:20:07 +01:00
GitHub Actions Bot
c84d8a0f6d Auto-update Wippersnapper definitions [skip ci] 2025-05-12 00:20:50 +00:00
GitHub Actions Bot
6daee3cad1 Auto-update Wippersnapper definitions [skip ci] 2025-05-11 00:21:01 +00:00
GitHub Actions Bot
ace03cfa4b Auto-update Wippersnapper definitions [skip ci] 2025-05-10 00:18:47 +00:00
GitHub Actions Bot
24b238c411 Auto-update Wippersnapper definitions [skip ci] 2025-05-09 00:19:48 +00:00
GitHub Actions Bot
0bbde5e157 Auto-update Wippersnapper definitions [skip ci] 2025-05-08 00:19:46 +00:00
GitHub Actions Bot
8c1c5ce333 Auto-update Wippersnapper definitions [skip ci] 2025-05-07 00:19:36 +00:00
GitHub Actions Bot
77b1a351a3 Auto-update Wippersnapper definitions [skip ci] 2025-05-06 00:19:38 +00:00
GitHub Actions Bot
28f9086d25 Auto-update Wippersnapper definitions [skip ci] 2025-05-05 00:20:52 +00:00
GitHub Actions Bot
96a4235b0d Auto-update Wippersnapper definitions [skip ci] 2025-05-04 00:21:42 +00:00
GitHub Actions Bot
df6b65bdf7 Auto-update Wippersnapper definitions [skip ci] 2025-05-03 00:18:58 +00:00
GitHub Actions Bot
20b7b73a33 Update submodules to latest versions [skip ci] 2025-05-03 00:18:40 +00:00
GitHub Actions Bot
3766e7bf16 Auto-update Wippersnapper definitions [skip ci] 2025-05-02 00:19:15 +00:00
GitHub Actions Bot
45455cfaf9 Auto-update Wippersnapper definitions [skip ci] 2025-05-01 00:21:39 +00:00
tyeth
0ada820901 Add GitHub Link 2025-04-30 12:56:13 +01:00
GitHub Actions Bot
2631d07976 Auto-update Wippersnapper definitions [skip ci] 2025-04-30 00:19:16 +00:00
GitHub Actions Bot
58f91746aa Auto-update Wippersnapper definitions [skip ci] 2025-04-29 17:49:45 +00:00
Tyeth Gundry
905543bfff
Update README.md 2025-04-29 14:30:50 +01:00
GitHub Actions Bot
fa550ae756 Auto-update Wippersnapper definitions [skip ci] 2025-04-29 13:22:08 +00:00
Tyeth Gundry
b4ecb3d3a5 Update import to be more robust and helpful 2025-04-29 14:21:04 +01:00
tyeth
878dd1e4db Add import suggestion text 2025-04-29 13:15:59 +01:00
GitHub Actions Bot
a733ad0317 Auto-update Wippersnapper definitions [skip ci] 2025-04-29 00:19:17 +00:00
tyeth
5a21ce6cce Stop components being added without pins specified 2025-04-28 21:39:23 +01:00
tyeth
74df0c938e Add help link 2025-04-28 19:08:09 +01:00
GitHub Actions Bot
3de8fea1d5 Auto-update Wippersnapper definitions [skip ci] 2025-04-28 14:00:42 +00:00
tyeth
c4277b95ee Fix companion board pin select on host 2025-04-28 14:57:40 +01:00
tyeth
6270941e2a Update board pins to have analog pins mixed in, and custom to have analog=pins, plus DIRECTION 2025-04-28 14:52:16 +01:00
tyeth
064bd2e040 Report compaion cs pin if not found on board 2025-04-28 14:41:12 +01:00
GitHub Actions Bot
e392458e4f Auto-update Wippersnapper definitions [skip ci] 2025-04-28 00:20:24 +00:00
GitHub Actions Bot
7f01135915 Auto-update Wippersnapper definitions [skip ci] 2025-04-27 00:21:02 +00:00
GitHub Actions Bot
3b70ba4bbf Auto-update Wippersnapper definitions [skip ci] 2025-04-26 00:18:46 +00:00
Tyeth Gundry
fd7126da46
typo: Update README.md 2025-04-26 00:59:11 +01:00
GitHub Actions Bot
29298b49b8 Auto-update Wippersnapper definitions [skip ci] 2025-04-25 23:55:51 +00:00
Tyeth Gundry
88596b23ba Find companion board pins 2025-04-26 00:53:29 +01:00
Tyeth Gundry
94139d0c4d Update attribution/license 2025-04-26 00:10:18 +01:00
Tyeth Gundry
838943d525 Remove used pins when alt bus unchecked 2025-04-25 23:48:05 +01:00
GitHub Actions Bot
aaac3cbac8 Auto-update Wippersnapper definitions [skip ci] 2025-04-25 22:21:22 +00:00
Tyeth Gundry
13246f747a
Use requirements file instead of manually specifying 2025-04-25 23:09:42 +01:00
Tyeth Gundry
c10d8b5407 Update definitions and readme 2025-04-25 23:02:28 +01:00
Tyeth Gundry
029c9bbf0e Merge branch 'use_boards_sd_card' 2025-04-25 21:43:53 +01:00
Tyeth Gundry
97b0030995 Merge branch 'use_boards_sd_card' of https://github.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator into use_boards_sd_card 2025-04-25 21:26:05 +01:00
Tyeth Gundry
9812af7654 Clear SD CS pin labels on companion change 2025-04-25 21:26:04 +01:00
GitHub Actions Bot
495fedb4ac Auto-update Wippersnapper definitions [skip ci] 2025-04-25 17:55:57 +00:00
Tyeth Gundry
a83314aa10 Helpful when you save the file to be commited 2025-04-25 18:54:53 +01:00
GitHub Actions Bot
8674eb81ea Auto-update Wippersnapper definitions [skip ci] 2025-04-25 17:49:26 +00:00
Tyeth Gundry
cea33ed69c Merge branch 'use_boards_sd_card' of https://github.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator into use_boards_sd_card 2025-04-25 18:48:55 +01:00
Tyeth Gundry
4e8de958c2 Correct manual override sd cs pin element ID 2025-04-25 18:48:53 +01:00
GitHub Actions Bot
3423400fbe Auto-update Wippersnapper definitions [skip ci] 2025-04-25 17:45:16 +00:00
Tyeth Gundry
ea79c82438 Correct pin to pin.number for appState.sdCardCS 2025-04-25 18:44:36 +01:00
GitHub Actions Bot
1db950963d Auto-update Wippersnapper definitions [skip ci] 2025-04-25 17:38:37 +00:00
Tyeth Gundry
0c4f9fd366 Show selected SD CS pin 2025-04-25 18:37:40 +01:00
GitHub Actions Bot
698cf890a8 Auto-update Wippersnapper definitions [skip ci] 2025-04-25 16:43:03 +00:00
Tyeth Gundry
5dd5e88eef Merge branch 'use_boards_sd_card' of https://github.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator into use_boards_sd_card 2025-04-25 17:40:35 +01:00
Tyeth Gundry
f762fd71d9 Correct pin.number for usedPins 2025-04-25 17:40:33 +01:00
GitHub Actions Bot
67f6b4c00b Auto-update Wippersnapper definitions [skip ci] 2025-04-25 16:38:49 +00:00
Tyeth Gundry
bc4eccec20 Update pin dropdown 2025-04-25 17:38:07 +01:00
Tyeth Gundry
9cca894e20 Add number to analog pins 2025-04-25 17:32:58 +01:00
GitHub Actions Bot
ba64f9bf5f Auto-update Wippersnapper definitions [skip ci] 2025-04-25 16:09:22 +00:00
tyeth
bbf48f8e41 Fix SD pin not resetting on companion change 2025-04-25 16:54:18 +01:00
tyeth
bb42bd4e5e Event handler changes 2025-04-25 16:54:04 +01:00
tyeth
b7acec2c40 Relabel import tab 2025-04-25 16:50:06 +01:00
GitHub Actions Bot
485cefb020 Auto-update Wippersnapper definitions [skip ci] 2025-04-24 00:19:24 +00:00
tyeth
ceb2140e02 Hide Export section from second tab 2025-04-22 19:01:23 +01:00
tyeth
172df1110d Update defs+firmware data 2025-04-22 18:51:20 +01:00
tyeth
83b54257a0 Update board image for companion boards + SDA/SCL case 2025-04-22 18:49:07 +01:00
GitHub Actions Bot
b0313d0d9b Auto-update Wippersnapper definitions [skip ci] 2025-04-12 00:18:20 +00:00
GitHub Actions Bot
dc2df8f6bf Auto-update Wippersnapper definitions [skip ci] 2025-04-11 17:23:37 +00:00
tyeth
70c4f18f23 ComponentAPI for Pin components is analogio or digitalio 2025-04-11 17:22:54 +01:00
tyeth
0575f0f0a9 Only accept INPUT pin components for now and use MODE 2025-04-11 17:15:37 +01:00
GitHub Actions Bot
6148f8a7f5 Auto-update Wippersnapper definitions [skip ci] 2025-04-11 14:27:47 +00:00
GitHub Actions Bot
ec034bcdc9 Update submodules to latest versions [skip ci] 2025-04-11 14:27:31 +00:00
tyeth
25bb96aec7 Update temporarily to default i2c address component defs 2025-04-11 01:50:07 +01:00
GitHub Actions Bot
cf4b3bdee8 Auto-update Wippersnapper definitions [skip ci] 2025-04-11 00:39:29 +00:00
GitHub Actions Bot
e360a24b86 Auto-update Wippersnapper definitions [skip ci] 2025-04-11 00:19:03 +00:00
GitHub Actions Bot
9a1c11aaff Auto-update Wippersnapper definitions [skip ci] 2025-04-10 20:37:06 +00:00
tyeth
1f0621f6a0 Merge branch 'use_boards_sd_card' of https://github.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator into use_boards_sd_card 2025-04-10 21:36:22 +01:00
tyeth
e09ad2d04b Update data types to handle complex objects 2025-04-10 21:36:19 +01:00
GitHub Actions Bot
9c2b562403 Auto-update Wippersnapper definitions [skip ci] 2025-04-10 20:32:56 +00:00
GitHub Actions Bot
1afea7a60e Auto-update Wippersnapper definitions [skip ci] 2025-04-10 20:14:26 +00:00
tyeth
e4eaf4e981 Add favicon link tag to header 2025-04-10 21:13:23 +01:00
GitHub Actions Bot
18d3d2ef7f Auto-update Wippersnapper definitions [skip ci] 2025-04-10 20:09:48 +00:00
tyeth
9b349bdd5e Component Cards: urls, datatypes and descriptions 2025-04-10 21:09:07 +01:00
tyeth
e6cae7daf4 Add docs urls to component info filter 2025-04-10 20:58:10 +01:00
tyeth
6c37524656 Add Mux info in both places + drop polling period 2025-04-10 20:52:33 +01:00
tyeth
2b55d72f1f Stop dupe search at L914 and L514 2025-04-10 20:41:08 +01:00
tyeth
7e56d2be60 Rename autoInit to autoConfig and default to false 2025-04-10 20:16:28 +01:00
GitHub Actions Bot
f0dc37476d Auto-update Wippersnapper definitions [skip ci] 2025-04-10 19:03:20 +00:00
tyeth
63eed1706b Merge branch 'use_boards_sd_card' of https://github.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator into use_boards_sd_card 2025-04-10 20:02:40 +01:00
tyeth
062ceeb175 CSS: Move search boxes and inline styles to classes. tighten paragraphs in board-details class 2025-04-10 20:02:35 +01:00
GitHub Actions Bot
6057d5fc02 Auto-update Wippersnapper definitions [skip ci] 2025-04-10 18:37:39 +00:00
tyeth
1c60b34570 Add favicon 2025-04-10 19:36:48 +01:00
GitHub Actions Bot
d8d60090f5 Auto-update Wippersnapper definitions [skip ci] 2025-04-10 18:34:15 +00:00
tyeth
8278ac5ca6 Companion boards have images and docs links 2025-04-10 19:33:15 +01:00
tyeth
9edd928f9e Product URLs for boards + companion boards (missing docs for companions) 2025-04-10 19:05:45 +01:00
tyeth
08d4b1ecba Add product urls and docs for boards 2025-04-10 18:42:38 +01:00
GitHub Actions Bot
8318e89de1 Auto-update Wippersnapper definitions [skip ci] 2025-04-10 17:16:49 +00:00
tyeth
f7bbde5253 Minor visual updates 2025-04-10 18:15:53 +01:00
GitHub Actions Bot
927c23e0d9 Auto-update Wippersnapper definitions [skip ci] 2025-04-10 16:31:55 +00:00
tyeth
35778c44ca Board gen assets 2025-04-10 17:29:10 +01:00
tyeth
e8f05b589d Auto Init false not true (still to rename autoConfig 2025-04-10 17:28:57 +01:00
tyeth
0e8ef5b752 WIP: Update workflow to use boards branch for submodule update 2025-04-10 17:28:33 +01:00
GitHub Actions Bot
c23f93581b Auto-update Wippersnapper definitions [skip ci] 2025-04-10 15:41:21 +00:00
GitHub Actions Bot
07ba330ffc Auto-update Wippersnapper definitions [skip ci] 2025-04-10 15:36:18 +00:00
tyeth
8c7570e874 Update release info JS filename for CI 2025-04-10 16:35:35 +01:00
tyeth
082579adf3 Update auto init checkbox 2025-04-10 16:34:21 +01:00
tyeth
eb5b338752 Add requests back to CI requirements 2025-04-10 16:32:17 +01:00
tyeth
42cf174531 Change workflow to push back to same branch 2025-04-10 16:29:56 +01:00
tyeth
becfb3b253 enable autoInit flag (but false for muxes), and components scrollbar 2025-04-10 16:27:27 +01:00
tyeth
ddbaa1da77 Add product urls and images for companion boards 2025-04-10 15:05:39 +01:00
tyeth
5f7613a86c Add companion board explanation 2025-04-10 14:50:09 +01:00
tyeth
a128c60bc6 Add Real-time clock mention for abbreviations 2025-04-10 14:49:48 +01:00
tyeth
7c5c43eb3e Update Adalogger RP2040 image 2025-04-10 14:31:57 +01:00
tyeth
a846c2b817 Update boards repo for Metro RP2350 image 2025-04-10 14:29:45 +01:00
tyeth
2cb48d7e63 Update missing board images, latest boards repo 2025-04-10 14:26:13 +01:00
tyeth
9c25415191 Update brightness slider step size 2025-04-10 14:14:34 +01:00
tyeth
8b1115e8f4 Update boards repo for adalogger CS pin 2025-04-10 14:14:23 +01:00
tyeth
df364ecbe7 Correct RTC value check from python to JS 2025-04-10 13:57:25 +01:00
tyeth
01597a353e Latest release/boards/components info 2025-04-10 13:47:05 +01:00
tyeth
3c95a984b9 Update header section for new title / sizing 2025-04-10 13:44:15 +01:00
tyeth
cffb9d5673 RTC warning/change 2025-04-10 13:43:47 +01:00
tyeth
c79f205daf Update boards commit (metro rp2350 installBoardName) 2025-04-10 13:42:43 +01:00
tyeth
2c9ca9b67b WIP: replace picow boards as pico, plus uf2 only and generic last 2025-04-09 23:31:46 +01:00
tyeth
bccb1224c1 Latest boards commit (drop rtc from adalogger) 2025-04-09 23:10:32 +01:00
tyeth
8a5bedcdc5 Add product urls for companion boards 2025-04-09 17:53:00 +01:00
tyeth
9315ad1ae5 Fix CS pin from boards, and displayName for muxes 2025-04-09 17:42:27 +01:00
tyeth
fc0cf89192 drop i2c bus selector from component search 2025-04-09 15:55:13 +01:00
tyeth
0ad3ab1a39 Broken pin selection for SD CS (sd-missing) 2025-04-09 15:54:53 +01:00
tyeth
c1e1c1e683 Update boards to have installBoardName for feather_rp2040_adalogger_tinyusb 2025-04-09 15:26:00 +01:00
tyeth
e915c8d68f Link firmware assets, add displayName for components 2025-04-09 15:24:19 +01:00
Tyeth Gundry
4cdffd1369
Update index.html - add RTC bus warning 2025-04-09 14:22:46 +01:00
tyeth
d8ca4c5336 WIP: set rp2040_datalogger_feather branch for board images 2025-04-09 13:35:07 +01:00
tyeth
e5cea990ca Pass through SD and RTC 2025-04-09 13:31:15 +01:00
tyeth
b7c9b5e748 rename firmware data file 2025-04-09 13:20:45 +01:00
tyeth
140e039775 Update to use rtc and sdCardCS in defs 2025-04-09 13:09:35 +01:00
tyeth
f69d82803b WIP: swap branch to use_barods_sd_card for defs 2025-04-09 13:05:39 +01:00
tyeth
fc696d5ad0 Update to fetch releases, use installBoardName 2025-04-09 13:05:01 +01:00
tyeth
4b8844a0e1 Fix images using product API 2025-04-09 12:52:54 +01:00
tyeth
d6243f25ba Switch to Offline boards branch, update components 2025-04-09 11:01:34 +01:00
GitHub Actions Bot
83034b8e03 Auto-update Wippersnapper definitions [skip ci] 2025-04-04 14:50:55 +00:00
21 changed files with 15412 additions and 12094 deletions

View file

@ -39,18 +39,26 @@ jobs:
run: |
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"
git submodule update --remote --recursive
git submodule init
git submodule update --recursive
cd Wippersnapper_Boards
git reset --hard origin/offline-mode
cd ../Wippersnapper_Components
git reset --hard origin/offline-mode
cd ..
git add Wippersnapper_Boards Wippersnapper_Components
git diff --staged --quiet || git commit -m "Update submodules to latest versions [skip ci]"
- name: Run conversion script
run: |
pip install requests beautifulsoup4
pip install -r requirements.txt
python convert_all_wippersnapper_definitions.py
- name: Commit changes if any
run: |
git add wippersnapper_boards.json wippersnapper_components.json
git add wippersnapper_boards.json wippersnapper_components.json wippersnapper_boards.js wippersnapper_components.js firmware-data.js
git diff --staged --quiet || git commit -m "Auto-update Wippersnapper definitions [skip ci]"
git push origin main
git push origin ${{ github.ref_name }}
- name: Setup Pages
uses: actions/configure-pages@v4

3
.gitignore vendored
View file

@ -3,3 +3,6 @@
__pycache__/
*.pyc
bin/
lib/
pyvenv.cfg

1
.gitmodules vendored
View file

@ -4,3 +4,4 @@
[submodule "Wippersnapper_Components"]
path = Wippersnapper_Components
url = https://github.com/adafruit/Wippersnapper_Components
branch = offline-mode

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2025 Tyeth Gundry
Copyright (c) 2025 Tyeth Gundry for Adafruit Industries
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,68 @@
# Adafruit_Wippersnapper_Offline_Configurator
A single web page for the creation / amending of config.json files to support Wippersnapper Offline Data Logger firmware
# Adafruit WipperSnapper Offline Configurator
This web page is for the creation / amending of `config.json` files to support the free and open-source Adafruit ["WipperSnapper"](https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/tree/offline-mode) Offline Data Logger firmware.
It allows users to select their microcontroller board, automatically (or manually) setup the Real Time Clock (RTC) and an SD card Chip Select pin (uses default SPI bus), or any companion boards with SD cards and/or RTCs, and then the attached components (sensors, analog pins, etc) for data logging.
The page can also be used offline by including the javascript (.js) files, ideally minified (180k > 60k), and index.html (i.e. copy to your device or SD card)
Visit the site here:
### [https://tyeth.github.io/Adafruit_Wippersnapper_Offline_Configurator/](https://tyeth.github.io/Adafruit_Wippersnapper_Offline_Configurator/)
[https://adafruit.github.io/Adafruit_Wippersnapper_Offline_Configurator/](https://adafruit.github.io/Adafruit_Wippersnapper_Offline_Configurator/)
See this Learn Guide for more info on using Adafruit Wippersnapper Firmware (offline mode) as a Data Logger, which also has the **Supported Hardware** page:
[No-Code Offline Data Logger with WipperSnapper](https://learn.adafruit.com/no-code-offline-data-logging-with-wippersnapper/)
## Development
We gratefully accept pull-requests and issues (open-source ❤️) although the main [Wippersnapper repository](https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/issues) is better suited for issues (or the [boards](https://github.com/adafruit/Wippersnapper_Boards) or [components](https://github.com/adafruit/Wippersnapper_Components) repos), as this is a stop-gap solution until the main Adafruit IO website performs the desired functionality (Wippersnapper v2), but it has proven useful so maybe will continue to do so.
If you wish to play with the website design / functionality then the main files to edit are:
* index.html
* load-wippersnapper-data.js
* wippersnapper-config-builder.js
The remaining files are involved in updating automatically generated board and component definitions.
#### Adding new components / boards / companion boards / RTCs
If you wish to add companion boards then those are manually defined (search featherwing), but boards and components should be added to WipperSnapper to be picked up automatically.
If you wish to add new RTCs, they must first be added to the offline firmware, and then we/you can add the RTC to the web interface. The repositories are linked above.
#### Running the board+component+firmware fetching/conversion process
To recreate the build process, which processes the boards+component definitions and fetches images + firmware versions, you'll need python installed (and pip) and then to install the requirements:
```shell
pip install -r requirements.txt
```
Then before running you'll need to initialise the submodules with git (or download the submodules and unzip manually)
```shell
git submodule update --init
```
Finally run the convert script:
```shell
python ./convert_all_wippersnapper_definitions.py
```
And you should see output like this:
```
=== Conversion Complete ===
Converted 23 boards and 98 components
Time taken: 24.39 seconds
Output files:
- C:\dev\js\Adafruit_Wippersnapper_Offline_Configurator\wippersnapper_boards.json
- C:\dev\js\Adafruit_Wippersnapper_Offline_Configurator\wippersnapper_components.json
- C:\dev\js\Adafruit_Wippersnapper_Offline_Configurator\firmware-data.js
```
That will have replaced the following files:
* wippersnapper_boards.js + .json
* wippersnapper_components.js + .json
* firmware-data.js
## Attribution
Written by Tyeth Gundry (with some "assistance"🤦 from Claude3.7/Copilot/GPT4), for Adafruit Industries.
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

@ -1 +1 @@
Subproject commit 86fd50d32b66abe1fbf8c9a1926f310308dc5bea
Subproject commit 941e94a52bbe1f33aed3328ddd0ec7a5f3adfbd0

@ -1 +1 @@
Subproject commit 848a7bc7fef4eb4701236ba2a0af4fb6f268e19d
Subproject commit dc7f57cb1697e4efc4e9490cc51b7ec569f32c15

View file

@ -2,6 +2,7 @@ import os
import time
from convert_boards_to_json import convert_boards_to_json
from convert_components_to_json import convert_components_to_json
from fetch_latest_release_info_and_assets import main as fetch_latest_release_info_and_assets
def main():
"""
@ -20,6 +21,9 @@ def main():
print("\n--- Converting Components ---")
components = convert_components_to_json()
# fetch latest release info and assets
release_info = fetch_latest_release_info_and_assets()
# Print summary
elapsed_time = time.time() - start_time
print("\n=== Conversion Complete ===")
@ -28,6 +32,7 @@ def main():
print(f"Output files:")
print(f" - {os.path.abspath(r'wippersnapper_boards.json')}")
print(f" - {os.path.abspath(r'wippersnapper_components.json')}")
print(f" - {os.path.abspath(r'firmware-data.json')}")
if __name__ == "__main__":
main()

View file

@ -2,6 +2,7 @@ import os
import json
import glob
from pathlib import Path
from convert_components_to_json import get_image_from_adafruit_product_url
# Base directory for the boards
BOARDS_DIR = r"./Wippersnapper_Boards/boards"
@ -11,57 +12,7 @@ def add_custom_board_definitions(boards):
"""
Add custom board definitions for boards that don't have definition.json files
"""
# Adafruit Feather RP2040 Adalogger
boards["feather-rp2040-adalogger"] = {
"boardName": "Adafruit Feather RP2040 Adalogger",
"mcuName": "RP2040",
"referenceVoltage": 3.3,
"displayName": "Adafruit Feather RP2040 Adalogger",
"vendor": "Adafruit",
"productURL": "https://www.adafruit.com/product/5980",
"documentationURL": "https://learn.adafruit.com/adafruit-feather-rp2040-adalogger",
"installMethod": "uf2",
"totalGPIOPins": 22,
"totalAnalogPins": 4,
"pins": [
{"number": 0, "name": "D0", "displayName": "GPIO0", "hasPWM": True, "hasServo": True},
{"number": 1, "name": "D1", "displayName": "GPIO1", "hasPWM": True, "hasServo": True},
{"number": 2, "name": "D2", "displayName": "GPIO2", "hasPWM": True, "hasServo": True},
{"number": 3, "name": "D3", "displayName": "GPIO3", "hasPWM": True, "hasServo": True},
{"number": 4, "name": "D4", "displayName": "GPIO4", "hasPWM": True, "hasServo": True},
{"number": 5, "name": "D5", "displayName": "GPIO5", "hasPWM": True, "hasServo": True},
{"number": 6, "name": "D6", "displayName": "GPIO6", "hasPWM": True, "hasServo": True},
{"number": 7, "name": "D7", "displayName": "GPIO7", "hasPWM": True, "hasServo": True},
{"number": 8, "name": "D8", "displayName": "GPIO8", "hasPWM": True, "hasServo": True},
{"number": 9, "name": "D9", "displayName": "GPIO9", "hasPWM": True, "hasServo": True},
{"number": 10, "name": "D10", "displayName": "GPIO10", "hasPWM": True, "hasServo": True},
{"number": 11, "name": "D11", "displayName": "GPIO11", "hasPWM": True, "hasServo": True},
{"number": 12, "name": "D12", "displayName": "GPIO12", "hasPWM": True, "hasServo": True},
{"number": 13, "name": "D13", "displayName": "GPIO13 (LED)", "hasPWM": True, "hasServo": True},
{"number": 16, "name": "D16", "displayName": "GPIO16 (MOSI)", "hasPWM": True, "hasServo": True},
{"number": 17, "name": "D17", "displayName": "GPIO17 (A1/SCK/SD CS)", "hasPWM": True, "hasServo": True},
{"number": 18, "name": "D18", "displayName": "GPIO18 (MISO)", "hasPWM": True, "hasServo": True},
{"number": 19, "name": "D19", "displayName": "GPIO19", "hasPWM": True, "hasServo": True},
{"number": 20, "name": "D20", "displayName": "GPIO20", "hasPWM": True, "hasServo": True},
{"number": 24, "name": "D24", "displayName": "GPIO24 (A0)", "hasPWM": True, "hasServo": True},
{"number": 25, "name": "D25", "displayName": "GPIO25 (A3)", "hasPWM": True, "hasServo": True},
{"number": 29, "name": "D29", "displayName": "GPIO29 (A2)", "hasPWM": True, "hasServo": True}
],
"analogPins": [
{"name": "A0", "displayName": "GPIO24 (A0)", "direction": "INPUT"},
{"name": "A1", "displayName": "GPIO17 (A1/SD CS)", "direction": "INPUT"},
{"name": "A2", "displayName": "GPIO29 (A2)", "direction": "INPUT"},
{"name": "A3", "displayName": "GPIO25 (A3)", "direction": "INPUT"}
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D3",
"SDA": "D2"
},
"sdCardCS": 17, # GPIO17/A1 is the SD card CS pin
"rtcType": "PCF8523", # Built-in RTC chip
"image": None
}
# Generic ESP32-S2 based board
boards["generic-esp32-s2"] = {
"boardName": "Generic ESP32-S2",
@ -72,6 +23,9 @@ def add_custom_board_definitions(boards):
"productURL": "",
"documentationURL": "",
"installMethod": "uf2",
"installBoardName": "",
"rtc": None,
"sdCardCS": None,
"totalGPIOPins": 43,
"totalAnalogPins": 20,
"pins": [
@ -123,8 +77,8 @@ def add_custom_board_definitions(boards):
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D9",
"SDA": "D8"
"SCL": 9,
"SDA": 8
},
"image": None
}
@ -139,6 +93,9 @@ def add_custom_board_definitions(boards):
"productURL": "",
"documentationURL": "",
"installMethod": "uf2",
"installBoardName": "",
"rtc": None,
"sdCardCS": None,
"totalGPIOPins": 48,
"totalAnalogPins": 20,
"pins": [
@ -192,8 +149,8 @@ def add_custom_board_definitions(boards):
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D9",
"SDA": "D8"
"SCL": 9,
"SDA": 8
},
"image": None
}
@ -208,6 +165,9 @@ def add_custom_board_definitions(boards):
"productURL": "",
"documentationURL": "",
"installMethod": "uf2",
"installBoardName": "",
"rtc": None,
"sdCardCS": None,
"totalGPIOPins": 30,
"totalAnalogPins": 4,
"pins": [
@ -250,8 +210,8 @@ def add_custom_board_definitions(boards):
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D3",
"SDA": "D2"
"SCL": 3,
"SDA": 2
},
"image": None
}
@ -261,13 +221,16 @@ def add_custom_board_definitions(boards):
"boardName": "Generic RP23xx",
"mcuName": "RP23xx",
"referenceVoltage": 3.3,
"displayName": "Generic RP23xx Board",
"displayName": "Generic RP2350/RP2354 board",
"vendor": "Generic",
"productURL": "",
"documentationURL": "",
"installMethod": "uf2",
"totalGPIOPins": 30,
"totalAnalogPins": 4,
"installBoardName": "",
"rtc": None,
"sdCardCS": None,
"totalGPIOPins": 48,
"totalAnalogPins": 8,
"pins": [
{"number": 0, "name": "D0", "displayName": "GPIO0", "hasPWM": True, "hasServo": True},
{"number": 1, "name": "D1", "displayName": "GPIO1", "hasPWM": True, "hasServo": True},
@ -295,83 +258,48 @@ def add_custom_board_definitions(boards):
{"number": 23, "name": "D23", "displayName": "GPIO23", "hasPWM": True, "hasServo": True},
{"number": 24, "name": "D24", "displayName": "GPIO24", "hasPWM": True, "hasServo": True},
{"number": 25, "name": "D25", "displayName": "GPIO25", "hasPWM": True, "hasServo": True},
{"number": 26, "name": "D26", "displayName": "GPIO26", "hasPWM": True, "hasServo": True},
{"number": 27, "name": "D27", "displayName": "GPIO27", "hasPWM": True, "hasServo": True},
{"number": 28, "name": "D28", "displayName": "GPIO28", "hasPWM": True, "hasServo": True},
{"number": 29, "name": "D29", "displayName": "GPIO29", "hasPWM": True, "hasServo": True}
{"number": 26, "name": "A26", "displayName": "GPIO26 (ADC0)", "hasPWM": True, "hasServo": True},
{"number": 27, "name": "A27", "displayName": "GPIO27 (ADC1)", "hasPWM": True, "hasServo": True},
{"number": 28, "name": "A28", "displayName": "GPIO28 (ADC2)", "hasPWM": True, "hasServo": True},
{"number": 29, "name": "A29", "displayName": "GPIO29 (ADC3)", "hasPWM": True, "hasServo": True},
{"number": 30, "name": "D30", "displayName": "GPIO30", "hasPWM": True, "hasServo": True},
{"number": 31, "name": "D31", "displayName": "GPIO31", "hasPWM": True, "hasServo": True},
{"number": 32, "name": "D32", "displayName": "GPIO32", "hasPWM": True, "hasServo": True},
{"number": 33, "name": "D33", "displayName": "GPIO33", "hasPWM": True, "hasServo": True},
{"number": 34, "name": "D34", "displayName": "GPIO34", "hasPWM": True, "hasServo": True},
{"number": 35, "name": "D35", "displayName": "GPIO35", "hasPWM": True, "hasServo": True},
{"number": 36, "name": "D36", "displayName": "GPIO36", "hasPWM": True, "hasServo": True},
{"number": 37, "name": "D37", "displayName": "GPIO37", "hasPWM": True, "hasServo": True},
{"number": 38, "name": "D38", "displayName": "GPIO38", "hasPWM": True, "hasServo": True},
{"number": 39, "name": "D39", "displayName": "GPIO39", "hasPWM": True, "hasServo": True},
{"number": 40, "name": "A40", "displayName": "GPIO40 (ADC0)", "hasPWM": True, "hasServo": True},
{"number": 41, "name": "A41", "displayName": "GPIO41 (ADC1)", "hasPWM": True, "hasServo": True},
{"number": 42, "name": "A42", "displayName": "GPIO42 (ADC2)", "hasPWM": True, "hasServo": True},
{"number": 43, "name": "A43", "displayName": "GPIO43 (ADC3)", "hasPWM": True, "hasServo": True},
{"number": 44, "name": "D44", "displayName": "GPIO44", "hasPWM": True, "hasServo": True},
{"number": 45, "name": "D45", "displayName": "GPIO45", "hasPWM": True, "hasServo": True},
{"number": 46, "name": "D46", "displayName": "GPIO46", "hasPWM": True, "hasServo": True},
{"number": 47, "name": "D47", "displayName": "GPIO47", "hasPWM": True, "hasServo": True},
{"number": 48, "name": "D48", "displayName": "GPIO48", "hasPWM": True, "hasServo": True}
],
"analogPins": [
{"name": "A0", "displayName": "ADC0", "direction": "INPUT"},
{"name": "A1", "displayName": "ADC1", "direction": "INPUT"},
{"name": "A2", "displayName": "ADC2", "direction": "INPUT"},
{"name": "A3", "displayName": "ADC3", "direction": "INPUT"}
{"name": "A26", "displayName": "GPIO26 (ADC0)", "direction": "INPUT"},
{"name": "A27", "displayName": "GPIO27 (ADC1)", "direction": "INPUT"},
{"name": "A28", "displayName": "GPIO28 (ADC2)", "direction": "INPUT"},
{"name": "A29", "displayName": "GPIO29 (ADC3)", "direction": "INPUT"},
{"name": "A40", "displayName": "GPIO40 (ADC0)", "direction": "INPUT"},
{"name": "A41", "displayName": "GPIO41 (ADC1)", "direction": "INPUT"},
{"name": "A42", "displayName": "GPIO42 (ADC2)", "direction": "INPUT"},
{"name": "A43", "displayName": "GPIO43 (ADC3)", "direction": "INPUT"}
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D3",
"SDA": "D2"
"SCL": 3,
"SDA": 2
},
"image": None
}
# Adafruit Metro RP2350 with SD card
boards["metro-rp2350-sd"] = {
"boardName": "Adafruit Metro RP2350",
"mcuName": "RP2350",
"referenceVoltage": 3.3,
"displayName": "Adafruit Metro RP2350 (with SD card)",
"vendor": "Adafruit",
"productURL": "https://www.adafruit.com/product/5786",
"documentationURL": "https://learn.adafruit.com/adafruit-metro-rp2350",
"installMethod": "uf2",
"totalGPIOPins": 30,
"totalAnalogPins": 4,
"pins": [
{"number": 0, "name": "D0", "displayName": "GPIO0", "hasPWM": True, "hasServo": True},
{"number": 1, "name": "D1", "displayName": "GPIO1", "hasPWM": True, "hasServo": True},
{"number": 2, "name": "D2", "displayName": "GPIO2", "hasPWM": True, "hasServo": True},
{"number": 3, "name": "D3", "displayName": "GPIO3", "hasPWM": True, "hasServo": True},
{"number": 4, "name": "D4", "displayName": "GPIO4", "hasPWM": True, "hasServo": True},
{"number": 5, "name": "D5", "displayName": "GPIO5", "hasPWM": True, "hasServo": True},
{"number": 6, "name": "D6", "displayName": "GPIO6", "hasPWM": True, "hasServo": True},
{"number": 7, "name": "D7", "displayName": "GPIO7", "hasPWM": True, "hasServo": True},
{"number": 8, "name": "D8", "displayName": "GPIO8", "hasPWM": True, "hasServo": True},
{"number": 9, "name": "D9", "displayName": "GPIO9", "hasPWM": True, "hasServo": True},
{"number": 10, "name": "D10", "displayName": "GPIO10 (SD CS)", "hasPWM": True, "hasServo": True},
{"number": 11, "name": "D11", "displayName": "GPIO11", "hasPWM": True, "hasServo": True},
{"number": 12, "name": "D12", "displayName": "GPIO12", "hasPWM": True, "hasServo": True},
{"number": 13, "name": "D13", "displayName": "GPIO13", "hasPWM": True, "hasServo": True},
{"number": 14, "name": "D14", "displayName": "GPIO14", "hasPWM": True, "hasServo": True},
{"number": 15, "name": "D15", "displayName": "GPIO15", "hasPWM": True, "hasServo": True},
{"number": 16, "name": "D16", "displayName": "GPIO16", "hasPWM": True, "hasServo": True},
{"number": 17, "name": "D17", "displayName": "GPIO17", "hasPWM": True, "hasServo": True},
{"number": 18, "name": "D18", "displayName": "GPIO18", "hasPWM": True, "hasServo": True},
{"number": 19, "name": "D19", "displayName": "GPIO19", "hasPWM": True, "hasServo": True},
{"number": 20, "name": "D20", "displayName": "GPIO20", "hasPWM": True, "hasServo": True},
{"number": 21, "name": "D21", "displayName": "GPIO21", "hasPWM": True, "hasServo": True},
{"number": 22, "name": "D22", "displayName": "GPIO22", "hasPWM": True, "hasServo": True},
{"number": 23, "name": "D23", "displayName": "GPIO23", "hasPWM": True, "hasServo": True},
{"number": 24, "name": "D24", "displayName": "GPIO24", "hasPWM": True, "hasServo": True},
{"number": 25, "name": "D25", "displayName": "GPIO25", "hasPWM": True, "hasServo": True},
{"number": 26, "name": "D26", "displayName": "GPIO26", "hasPWM": True, "hasServo": True},
{"number": 27, "name": "D27", "displayName": "GPIO27", "hasPWM": True, "hasServo": True},
{"number": 28, "name": "D28", "displayName": "GPIO28", "hasPWM": True, "hasServo": True},
{"number": 29, "name": "D29", "displayName": "GPIO29", "hasPWM": True, "hasServo": True}
],
"analogPins": [
{"name": "A0", "displayName": "ADC0", "direction": "INPUT"},
{"name": "A1", "displayName": "ADC1", "direction": "INPUT"},
{"name": "A2", "displayName": "ADC2", "direction": "INPUT"},
{"name": "A3", "displayName": "ADC3", "direction": "INPUT"}
],
"defaultI2C": {
"i2cPortId": 0,
"SCL": "D3",
"SDA": "D2"
},
"sdCardCS": 10,
"image": None
}
return boards
@ -409,18 +337,28 @@ def convert_boards_to_json():
"productURL": board_data.get("productURL", ""),
"documentationURL": board_data.get("documentationURL", ""),
"installMethod": board_data.get("installMethod", ""),
"installBoardName": board_data.get("installBoardName", board_data.get("boardName", "")),
"rtc": board_data.get("rtc", None),
"sdCardCS": board_data.get("sdCardCS", None),
"pins": [],
"analogPins": [],
"defaultI2C": {},
"image": None
}
SUPPORTED_ARCHITECTURES = ["rp2350", "rp2040", "esp32s2", "esp32s3"]
# Filter out boards that are not supported
if board_info["mcuName"] not in SUPPORTED_ARCHITECTURES:
print(f"Skipping {board_dir} - Unsupported architecture {board_info['mcuName']}")
continue
# Get pins
if "components" in board_data and "digitalPins" in board_data["components"]:
for pin in board_data["components"]["digitalPins"]:
# Extract the numeric part of the pin name (e.g., "D13" -> 13)
pin_name = pin.get("name", "")
if pin_name.startswith("D"):
# if board_info["pins"].filter(lambda x: x["name"] == pin_name) == 0:
try:
pin_number = int(pin_name[1:])
board_info["pins"].append({
@ -428,7 +366,8 @@ def convert_boards_to_json():
"name": pin_name,
"displayName": pin.get("displayName", pin_name),
"hasPWM": pin.get("hasPWM", False),
"hasServo": pin.get("hasServo", False)
"hasServo": pin.get("hasServo", False),
"direction": pin.get("direction", "")
})
except ValueError:
print(f"Skipping pin {pin_name} - Cannot parse pin number")
@ -438,12 +377,27 @@ def convert_boards_to_json():
analog_count = 0
for pin in board_data["components"]["analogPins"]:
pin_name = pin.get("name", "")
try:
pin_number = int(pin_name[1:])
board_info["analogPins"].append({
"number": pin_number,
"name": pin_name,
"displayName": pin.get("displayName", pin_name),
"direction": pin.get("direction", "INPUT")
"direction": pin.get("direction", "")
})
analog_count += 1
# Add to pins list as well if number not already present
if not any(p["number"] == pin_number for p in board_info["pins"]):
board_info["pins"].append({
"number": pin_number,
"name": pin_name,
"displayName": pin.get("displayName", pin_name),
"direction": "", # Blank for both input and output
"hasPWM": True,
"hasServo": True
})
except ValueError:
print(f"Skipping pin {pin_name} - Cannot parse pin number")
board_info["totalAnalogPins"] = analog_count
# Get I2C ports
@ -472,6 +426,10 @@ def convert_boards_to_json():
board_info["image"] = f"boards/{board_dir}/image{ext}"
break
# Fetch missing images
if board_info["image"] is None and board_info["productURL"] != "":
board_info["image"] = get_image_from_adafruit_product_url(board_info["productURL"])
# Add to boards dictionary
boards[board_dir] = board_info
print(f"Processed {board_dir}")

View file

@ -3,7 +3,7 @@ import json
import glob
import re
import requests
from bs4 import BeautifulSoup
# from bs4 import BeautifulSoup
from pathlib import Path
# Base directory for the components
@ -12,8 +12,8 @@ OUTPUT_FILE = r"./wippersnapper_components.json"
def get_image_from_adafruit_product_url(product_url):
"""
Fetch the product image URL from an Adafruit product page by extracting
the og:image meta tag from the HTML.
Fetch the product image URL from an Adafruit product API
(was from prod page by extracting the og:image meta tag from the HTML).
Args:
product_url (str): URL to an Adafruit product page
@ -21,29 +21,44 @@ def get_image_from_adafruit_product_url(product_url):
Returns:
str or None: URL to the product image, or None if not found
"""
if not product_url or not re.match(r'https?://(?:www\.)?adafruit\.com/product/\d+', product_url):
if not product_url or not re.match(r'https?://(?:www\.)?adafruit\.com/(?:product|category)/\d+', product_url):
print(f"Invalid Adafruit product URL ({product_url}) provided. Skipping image fetch.")
return None
# Grab product JSON from https://www.adafruit.com/api/products, cache, save as ISO date string filename so can be easily used as cache key
try:
response = requests.get(product_url, timeout=10)
product_id = re.search(r'/product/(\d+)', product_url)
category = re.search(r'/category/(\d+)', product_url)
url_to_fetch = f"https://www.adafruit.com/api/{("category" if category else "product")}/{(product_id.groups(1)[0] if product_id else category.groups(1)[0])}"
print(f"Fetching image from Adafruit API for {product_url}...\nGET {url_to_fetch}")
response = requests.get(url_to_fetch, timeout=10)
if response.status_code != 200:
print(f"Failed to fetch product page: {product_url}, status code: {response.status_code}")
print(f"Failed to fetch product data: {product_url}, status code: {response.status_code}")
return None
response_json = response.json()
if (response_json is None or response_json == [] or response_json == {} or 'error' in response_json):
print(f"Invalid response from API for {product_url}: {response_json}")
return None
soup = BeautifulSoup(response.text, 'html.parser')
og_image = soup.find('meta', property='og:image')
if og_image and 'content' in og_image.attrs:
image_url = og_image['content']
print(f"Found image URL from product page: {image_url}")
if 'product_image' in response_json:
image_url = response_json['product_image']
print(f"Found image URL from API: {image_url}")
return image_url
else:
print(f"No og:image meta tag found for: {product_url}")
elif 'subcategories' in response_json:
subcategories = response_json['subcategories']
for subcategory in subcategories:
if 'product_image' in subcategory:
image_url = subcategory['product_image']
print(f"Found image URL from API: {image_url}")
return image_url
print(f"No image found in subcategory for: {product_url}")
return None
except Exception as e:
print(f"Error fetching image from product URL {product_url}: {str(e)}")
print(f"Error fetching image from API for {product_url}: {str(e)}")
return None
## Consider removing beautifulsoup...
def map_datatypes_to_offline_types(datatype):
"""
Map datatypes to offline types.
@ -84,9 +99,15 @@ def convert_components_to_json():
with open(definition_file, 'r') as f:
component_data = json.load(f)
# Skip non-input components for now
if category == "pin":
if component_data.get("direction", "").lower() != "input":
continue
# Extract relevant information
component_info = {
"id": component_dir,
"displayName": component_data.get("displayName", component_dir),
"name": component_data.get("name", component_dir),
"description": component_data.get("description", ""),
"category": category,
@ -98,6 +119,10 @@ def convert_components_to_json():
if "productURL" in component_data:
component_info["productUrl"] = component_data["productURL"]
# store documentation URL if available
if "documentationURL" in component_data:
component_info["documentationUrl"] = component_data["documentationURL"]
# Extract data types if available
if "subcomponents" in component_data:
for meas_type in component_data["subcomponents"]:
@ -109,6 +134,10 @@ def convert_components_to_json():
else:
component_info["dataTypes"].append(map_datatypes_to_offline_types(meas_type))
# Handle pin category (MODE becomes componentAPI value)
if category == "pin":
component_info["componentAPI"] = component_data.get("mode", "digital").lower() + "io"
# Handle I2C-specific properties
if category == "i2c":
# Extract I2C address from parameters
@ -128,6 +157,69 @@ def convert_components_to_json():
else:
component_info["channels"] = 4
# Special handling for GPS over I2C
if component_data.get("isGps", False):
component_info["isGps"] = True
component_info["gps"] = {}
gps_data = component_data.get("gps", {})
component_info["gps"]["period"] = gps_data.get("period", 30000)
if "commands_ubxes" in gps_data:
component_info["gps"]["commands_ubxes"] = gps_data["commands_ubxes"]
if "commands_pmtks" in gps_data:
component_info["gps"]["commands_pmtks"] = gps_data["commands_pmtks"]
# Handle UART-specific properties
if category == "uart":
# Required properties
component_info["deviceType"] = component_data.get("deviceType")
component_info["deviceId"] = component_data.get("deviceId")
# Specific deviceType properties
if component_info["deviceType"] == "generic_input":
component_info["generic_input"] = {}
generic_input_data = component_data.get("generic_input", {})
component_info["generic_input"]["period"] = generic_input_data.get("period", 30000)
# Extract data types
if "generic_input" in component_data and "sensor_types" in component_data["generic_input"]:
for meas_type in component_data["generic_input"]["sensor_types"]:
if isinstance(meas_type, dict) and "sensorType" in meas_type:
component_info["dataTypes"].append({
"displayName": meas_type["displayName"] if "displayName" in meas_type else meas_type["sensorType"],
"sensorType": map_datatypes_to_offline_types(meas_type["sensorType"]) if "sensorType" in meas_type else None
})
else:
component_info["dataTypes"].append(map_datatypes_to_offline_types(meas_type))
elif component_info["deviceType"] == "gps":
component_info["gps"] = {}
gps_data = component_data.get("gps", {})
component_info["gps"]["period"] = gps_data.get("period", 30000)
if "commands_ubxes" in gps_data:
component_info["gps"]["commands_ubxes"] = gps_data["commands_ubxes"]
if "commands_pmtks" in gps_data:
component_info["gps"]["commands_pmtks"] = gps_data["commands_pmtks"]
elif component_info["deviceType"] == "pm25aqi":
component_info["pm25aqi"] = {}
# Parse PM2.5 AQI properties
if "pm25aqi" in component_data:
component_info["pm25aqi"]["period"] = component_data["pm25aqi"].get("period", 30000) # Default to 30s if not specified
if component_data["pm25aqi"].get("is_pm1006", False):
component_info["pm25aqi"]["is_pm1006"] = True
# Extract data types
pm25aqi_data = component_data
if "pm25aqi" in pm25aqi_data and "sensor_types" in pm25aqi_data["pm25aqi"]:
for meas_type in pm25aqi_data["pm25aqi"]["sensor_types"]:
if isinstance(meas_type, dict) and "sensorType" in meas_type:
component_info["dataTypes"].append({
"displayName": meas_type["displayName"] if "displayName" in meas_type else meas_type["sensorType"],
"sensorType": map_datatypes_to_offline_types(meas_type["sensorType"]) if "sensorType" in meas_type else None
})
else:
component_info["dataTypes"].append(map_datatypes_to_offline_types(meas_type))
elif component_info["deviceType"] == "tmc22xx":
# TODO
pass
else:
raise ValueError(f"Unknown deviceType {component_info['deviceType']} for {category}/{component_dir}")
# Look for an image file
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.svg']
image_found = False
@ -178,12 +270,12 @@ def convert_components_to_json():
# Write the consolidated JSON file
with open(OUTPUT_FILE, 'w') as f:
json.dump({"components": components}, f, indent=2)
json.dump({"components": components}, f, ensure_ascii=False, indent=2)
# Write the consolidated JS file
with open(OUTPUT_FILE.replace('.json', '.js'), 'w') as f:
f.write("window.jsonComponentsObject = ")
json.dump({"components": components}, f, indent=2)
json.dump({"components": components}, f, ensure_ascii=False, indent=2)
f.write(";\n")
print(f"Successfully created {OUTPUT_FILE}")

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View file

@ -0,0 +1,212 @@
# Take releases for wippersnapper, filtered to semver including -offline, get next page until finished if none.
# Later match board name to installBoardName from boards (which falls back to boardName)
import requests
import json
import os
from datetime import datetime
# Configuration
REPO = "adafruit/Adafruit_Wippersnapper_Arduino"
OUTPUT_DIR = "latest_firmware"
RELEASES_API_URL = f"https://api.github.com/repos/{REPO}/releases"
PER_PAGE = 30 # GitHub API default per page limit
JS_OUTPUT_FILE = "firmware-data.js"
def fetch_latest_offline_release():
"""Fetch the latest offline release from GitHub API."""
print(f"Fetching releases information for {REPO}...")
headers = {
"Accept": "application/vnd.github.v3+json"
}
all_releases = []
page = 1
found_offline_release = False
latest_offline_release = None
# Loop through pages until we find an offline release or run out of releases
while not found_offline_release:
page_url = f"{RELEASES_API_URL}?page={page}&per_page={PER_PAGE}"
print(f"Fetching page {page} of releases...")
response = requests.get(page_url, headers=headers)
response.raise_for_status()
page_releases = response.json()
all_releases.extend(page_releases)
# Check if this page contains any offline releases
offline_releases = [r for r in page_releases if "offline" in r.get("tag_name", "")]
offline_releases_count = len(offline_releases)
print(f"Found {offline_releases_count} offline releases on page {page}")
if offline_releases_count > 0:
found_offline_release = True
# Get the latest offline release by published date
latest_offline_release = sorted(
offline_releases,
key=lambda x: x.get("published_at", ""),
reverse=True
)[0]
break
# Move to next page if we didn't find any offline releases and there are more pages
page += 1
# Stop if we received fewer items than the per_page limit (meaning we're on the last page)
if len(page_releases) < PER_PAGE:
print(f"Reached the last page with {len(page_releases)} items (less than {PER_PAGE} per page)")
break
# Check if we found an offline release
if latest_offline_release is None:
raise Exception(f"No offline release found after checking {page} pages of releases.")
tag_name = latest_offline_release.get("tag_name")
release_name = latest_offline_release.get("name")
release_id = latest_offline_release.get("id")
release_html_url = latest_offline_release.get("html_url")
release_published_date = latest_offline_release.get("published_at")
print(f"Found latest offline release: {release_name} (Tag: {tag_name}, ID: {release_id})")
return latest_offline_release, release_id, tag_name, release_name, release_html_url, release_published_date
def fetch_release_assets(release_id):
"""Fetch all assets for a specific release."""
assets_url = f"https://api.github.com/repos/{REPO}/releases/{release_id}/assets"
print(f"Fetching complete assets list from: {assets_url}")
headers = {
"Accept": "application/vnd.github.v3+json"
}
all_assets = []
assets_page = 1
# Loop through pages to get all assets
while True:
assets_page_url = f"{assets_url}?page={assets_page}&per_page={PER_PAGE}"
print(f"Fetching page {assets_page} of assets...")
response = requests.get(assets_page_url, headers=headers)
response.raise_for_status()
page_assets = response.json()
# Add to all assets - ensure it's a list
if isinstance(page_assets, list):
all_assets.extend(page_assets)
else:
all_assets.append(page_assets)
# Move to next page if there are more assets
assets_page += 1
# Stop if we received fewer items than the per_page limit (meaning we're on the last page)
if len(page_assets) < PER_PAGE:
print(f"Reached the last page of assets with {len(page_assets)} items")
break
# Filter for UF2 files
print("Filtering for firmware files...")
firmware_assets = [
asset for asset in all_assets
if asset.get("name", "").endswith(".uf2")# or asset.get("name", "").endswith(".bin")
]
# Check if we found any assets
if len(firmware_assets) == 0:
print(f"No firmware files (.uf2) found in this release.")
return firmware_assets
def generate_js_data(release_info, assets):
"""Generate JavaScript data structure with firmware information."""
tag_name, release_name, release_html_url, release_published_date = release_info
# Format the published date
try:
dt = datetime.fromisoformat(release_published_date.replace("Z", "+00:00"))
formatted_date = dt.strftime("%Y-%m-%d")
except:
formatted_date = release_published_date
# Create firmware data object
firmware_data = {
"releaseInfo": {
"version": tag_name,
"name": release_name,
"url": release_html_url,
"publishedDate": formatted_date
},
"firmwareFiles": []
}
# Add firmware files info
for asset in assets:
if asset.get("name", "").endswith(".uf2") or asset.get("name", "").endswith(".bin"):
firmware_data["firmwareFiles"].append({
"name": asset.get("name"),
"url": asset.get("browser_download_url"),
"size": asset.get("size"),
"downloadCount": asset.get("download_count", 0),
"contentType": asset.get("content_type"),
"createdAt": asset.get("created_at")
})
return firmware_data
def save_js_data(firmware_data):
"""Save firmware data as a JavaScript file."""
js_content = f"""// Auto-generated on {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
const FIRMWARE_DATA = {json.dumps(firmware_data, indent=2)};
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {{
module.exports = {{ FIRMWARE_DATA }};
}} else {{
window.FIRMWARE_DATA = FIRMWARE_DATA;
}}
"""
with open(JS_OUTPUT_FILE, "w") as f:
f.write(js_content)
print(f"JavaScript data saved to {JS_OUTPUT_FILE}")
def main():
try:
# Create output directory if it doesn't exist
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
print(f"Created directory: {OUTPUT_DIR}")
# Fetch latest offline release
release_data, release_id, tag_name, release_name, release_html_url, release_published_date = fetch_latest_offline_release()
# Fetch assets for this release
firmware_assets = fetch_release_assets(release_id)
print(f"Found {len(firmware_assets)} firmware files.")
# Generate JavaScript data
firmware_data = generate_js_data(
(tag_name, release_name, release_html_url, release_published_date),
firmware_assets
)
# Save as JavaScript file
save_js_data(firmware_data)
print("Process completed successfully.")
except Exception as e:
print(f"Error: {str(e)}")
if __name__ == "__main__":
main()

162
firmware-data.js Normal file
View file

@ -0,0 +1,162 @@
// Auto-generated on 2025-08-29 00:19:42
const FIRMWARE_DATA = {
"releaseInfo": {
"version": "1.0.0-offline-beta.4",
"name": "WipperSnapper Offline 1.0.0-offline-beta.4",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/tag/1.0.0-offline-beta.4",
"publishedDate": "2025-08-18"
},
"firmwareFiles": [
{
"name": "wippersnapper.esp32s3_devkitc_1_n8.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.esp32s3_devkitc_1_n8.1.0.0-offline-beta.4.uf2",
"size": 3044864,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s2.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s2.1.0.0-offline-beta.4.uf2",
"size": 2990080,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s2_reverse_tft.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s2_reverse_tft.1.0.0-offline-beta.4.uf2",
"size": 2990080,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s2_tft.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s2_tft.1.0.0-offline-beta.4.uf2",
"size": 2990080,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s3.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s3.1.0.0-offline-beta.4.uf2",
"size": 3044864,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s3_4mbflash_2mbpsram.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s3_4mbflash_2mbpsram.1.0.0-offline-beta.4.uf2",
"size": 3050496,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s3_reverse_tft.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s3_reverse_tft.1.0.0-offline-beta.4.uf2",
"size": 3050496,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_esp32s3_tft.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_esp32s3_tft.1.0.0-offline-beta.4.uf2",
"size": 3050496,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.feather_rp2040_adalogger_tinyusb.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.feather_rp2040_adalogger_tinyusb.1.0.0-offline-beta.4.uf2",
"size": 863232,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.metroesp32s2.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.metroesp32s2.1.0.0-offline-beta.4.uf2",
"size": 2989568,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.metro_esp32s3.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.metro_esp32s3.1.0.0-offline-beta.4.uf2",
"size": 3054592,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.metro_rp2350_tinyusb.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.metro_rp2350_tinyusb.1.0.0-offline-beta.4.uf2",
"size": 872960,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.pico_rp2040_tinyusb.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.pico_rp2040_tinyusb.1.0.0-offline-beta.4.uf2",
"size": 862208,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.pico_rp2350_tinyusb.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.pico_rp2350_tinyusb.1.0.0-offline-beta.4.uf2",
"size": 858112,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.qtpy_esp32s2.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.qtpy_esp32s2.1.0.0-offline-beta.4.uf2",
"size": 2989568,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.qtpy_esp32s3.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.qtpy_esp32s3.1.0.0-offline-beta.4.uf2",
"size": 3044352,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.qtpy_esp32s3_n4r2.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.qtpy_esp32s3_n4r2.1.0.0-offline-beta.4.uf2",
"size": 3050496,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
},
{
"name": "wippersnapper.xiao_esp32s3.1.0.0-offline-beta.4.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.4/wippersnapper.xiao_esp32s3.1.0.0-offline-beta.4.uf2",
"size": 3145728,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
}
]
};
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = { FIRMWARE_DATA };
} else {
window.FIRMWARE_DATA = FIRMWARE_DATA;
}

View file

@ -3,8 +3,26 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="favicon.ico" type="image/x-icon">
<title>Wippersnapper Configuration Builder</title>
<style>
a.gh-link {
text-decoration: none;
}
a:hover.gh-link, a:focus.gh-link{
border-bottom: double 1px black;
}
.not-available-yet {
text-decoration: line-through;
font-size: x-small;
}
.component-tabcontent > h3 {
display: inline-block;
padding-right: 20px;
}
.component-tabcontent > .search-filter {
display: inline-block;
}
body {
font-family: Arial, sans-serif;
line-height: 1.6;
@ -45,6 +63,9 @@
display: flex;
flex-wrap: wrap;
gap: 10px;
scrollbar-width: auto;
max-height: 80vh;
overflow: scroll;
}
.component-card {
border: 1px solid #ddd;
@ -53,6 +74,12 @@
width: 230px;
background-color: white;
}
.component-card h4 {
margin: 0 0 10px 0;
}
.component-card p {
margin: 0 0 10px 0;
}
.component-card img {
max-width: 100%;
height: auto;
@ -94,11 +121,26 @@
.hidden {
display: none;
}
.i2c-bus-config {
.inline-row {
display: flex;
align-items: center;
align-content:space-around;
margin-bottom: 10px;
}
.dashed-section {
margin: 10px 0;
padding: 10px;
border: 1px dashed #ccc;
border-radius: 4px;
}
.dashed-section h3{
padding-top: 0px;
margin-top:0px;
}
.dashed-section > :last-child {
padding-bottom: 0px;
margin-bottom: 0px;
}
.tab {
overflow: hidden;
@ -184,6 +226,9 @@
.board-details {
flex: 1;
}
.board-details > p {
margin: 5px 0 0 0;
}
.search-filter {
margin-bottom: 15px;
}
@ -195,13 +240,29 @@
border: 1px solid #ddd;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div style="text-align: center; position: absolute; top: 5px; left: 5px;">
<a href="https://github.com/adafruit/Adafruit_Wippersnapper_Offline_Configurator" target="_blank" class="gh-link">
<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" alt="GitHub Logo" style="width: 30px; height: 30px; vertical-align: middle;">
<span style="font-size: 16px; vertical-align: middle;">Issues?</span>
</a>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<h1>Wippersnapper Configuration Builder</h1>
<div style="flex: 1;">
<h1>Wippersnapper Offline <a href="https://learn.adafruit.com/no-code-offline-data-logging-with-wippersnapper">[?]</a><br/>Data Logger Configurator</h1>
</div>
<div style="flex: 1; text-align: right;">
<div style="display:inline-block; font-size: smaller;"><b>Latest Release:</b> <a id="release_name" href="https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases">Release Page</a></div>
<div style="display:inline-block; margin: 5px; font-size: smaller;">Download: &nbsp;<a style="display: inline-flex;" id="firmware_file" href="https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases">UF2 firmware</a> </div>
</div>
<div style="flex: 1; text-align: right;">
<button id="reset-config-btn-top" class="reset-btn" style="background-color: #dc3545; margin-left: 20px;">Reset Configurator</button>
</div>
</div>
<!-- Loading indicator -->
<div id="loading-indicator" class="section">
@ -212,12 +273,13 @@
<div class="tab">
<button class="tablinks active" onclick="openTab(event, 'BuildConfig')">Build Configuration</button>
<button class="tablinks" onclick="openTab(event, 'ImportExport')">Import/Export</button>
<button class="tablinks" onclick="openTab(event, 'ImportExport')">Import Config / Custom Board</button>
</div>
<div id="BuildConfig" class="tabcontent" style="display: block;">
<div class="section">
<h2>1. Select Board</h2>
<p><small>You may wish to use the IMPORT option above <i>first</i>, or the Reset button to clear the configuration completely.</small></p>
<select id="board-select">
<option value="">-- Select a Board --</option>
<!-- Board options will be dynamically populated -->
@ -227,11 +289,11 @@
<div class="board-preview">
<img id="board-image" class="board-image hidden" src="" alt="Board image">
<div class="board-details">
<h3>Board Details</h3>
<h3>Board Details <span id="board-purchase"></span> <span id="board-help"></span></h3>
<p><strong>Reference Voltage:</strong> <span id="ref-voltage">3.3</span>V</p>
<p><strong>Total GPIO Pins:</strong> <span id="total-gpio">0</span></p>
<p><strong>Total Analog Pins:</strong> <span id="total-analog">0</span></p>
<p><strong>Default I2C Bus:</strong> SCL: <span id="default-scl">0</span>, SDA: <span id="default-sda">0</span></p>
<p><strong>Default I2C Bus:</strong> SCL: <span id="default-SCL">0</span>, SDA: <span id="default-SDA">0</span></p>
</div>
</div>
</div>
@ -239,7 +301,8 @@
<div id="companion-board-section" class="section hidden">
<h2>2. Select Companion Board (Optional)</h2>
<p>You can skip this step if you're not using a companion board.</p>
<p>You can skip this step if you're not using a companion board.
<br/><i><small>It's just a convenient way to prepopulate the Real-time clock model and SD Card's Chip Select pin option.</small></i></p>
<select id="companion-board-select">
<option value="">-- None --</option>
<option value="adalogger">Adafruit Adalogger FeatherWing</option>
@ -251,28 +314,34 @@
<option value="microsd-bff">Adafruit microSD Card BFF Add-On for QT Py and Xiao</option>
<option value="winc1500-shield">Adafruit WINC1500 WiFi Shield</option>
<option value="airlift-shield">Adafruit AirLift Shield - ESP32 WiFi Co-Processor</option>
<option value="seeed-xiao-s3sense-camera-addon">Seeed Studio XIAO ESP32S3 Sense Camera/SD Add-on board</option>
<option value="seeed-xiao-ssd1306-expansion-base">Seeed Studio XIAO Expansion base board</option>
</select>
<div id="companion-details" class="hidden">
<h3>Companion Board Details</h3>
<p><strong>RTC:</strong> <span id="companion-rtc">None</span></p>
<div class="board-preview">
<img id="companion-image" class="board-image hidden" src="#" alt="Companion board image">
<div class="board-details">
<h3>Companion Board Details <span id="companion-purchase"></span> <span id="companion-help"></span></h3>
<p><strong>Real-time clock (RTC):</strong> <span id="companion-rtc">None</span></p>
<p><strong>SD Card CS Pin:</strong> <span id="companion-sd-cs">None</span></p>
<p><strong>Additional Components:</strong> <span id="companion-extras">None</span></p>
</div>
</div>
</div>
</div>
<div id="manual-config-section" class="section hidden">
<h2>3. Manual Configuration</h2>
<div id="sd-card-config">
<div id="sd-card-config" class="dashed-section">
<h3>SD Card Configuration</h3>
<div id="sd-missing">
<p>No SD card detected from companion board. Would you like to add an SD card? <b>(REQUIRED)</b></p>
<label><input type="checkbox" id="add-sd-card"> Add SD Card</label>
<div id="sd-card-pin-select" class="hidden">
<p>Select SD Card CS Pin:</p>
<p>Selected SD Card CS Pin: <span id="manual-sd-cs-pin"></span></p>
<div id="sd-pins-list" class="pins-container"></div>
</div>
</div>
@ -281,13 +350,16 @@
</div>
</div>
<div id="rtc-config">
<h3>RTC Configuration</h3>
<div id="rtc-config" class="dashed-section">
<h3>Real-time clock (RTC) Configuration</h3>
<p style="color: red; font-weight: bold;">Note: The RTC must be on the first (default) I2C bus.</p>
<div id="rtc-missing">
<p>No RTC detected from companion board. Select RTC type:</p>
<p>No RTC detected from companion board.</p>
<label for="rtc-select">Select RTC type: </label>
<select id="rtc-select">
<option value="soft">Software RTC</option>
<option value="PCF8523">PCF8523</option>
<option value="PCF8563">PCF8563</option>
<option value="DS3231">DS3231</option>
<option value="DS1307">DS1307</option>
</select>
@ -297,35 +369,37 @@
</div>
</div>
<div id="status-led-config">
<div id="status-led-config" class="dashed-section">
<h3>Status LED Configuration</h3>
<div class="inline-row">
<label for="led-brightness">Status LED Brightness (0.0-1.0): </label>
<input type="range" id="led-brightness" min="0" max="1" step="0.1" value="0.5">
<input type="range" id="led-brightness" min="0" max="1" step="0.01" value="0.5">
<span id="brightness-value">0.5</span>
</div>
</div>
</div>
<div id="i2c-bus-section" class="section hidden">
<h2>4. I2C Bus Configuration</h2>
<div id="default-i2c-bus" class="i2c-bus-config">
<div id="default-i2c-bus" class="dashed-section">
<h3>Default I2C Bus</h3>
<p>SCL: <span id="default-i2c-scl"></span>, SDA: <span id="default-i2c-sda"></span></p>
<p>SCL: <span id="default-i2c-SCL"></span>, SDA: <span id="default-i2c-SDA"></span></p>
</div>
<div id="additional-i2c-bus-container">
<div id="additional-i2c-bus-container" class="dashed-section">
<h3>Additional I2C Bus (Optional)</h3>
<label><input type="checkbox" id="add-i2c-bus"> Add Additional I2C Bus</label>
<div id="additional-i2c-config" class="hidden i2c-bus-config">
<p>Select SCL Pin:</p>
<div id="scl-pins-list" class="pins-container"></div>
<p>Select SDA Pin:</p>
<div id="sda-pins-list" class="pins-container"></div>
<div id="additional-i2c-config" class="hidden dashed-section">
<p>Select SCL Pin: <span id="alt-SCL-pin"></span></p>
<div id="SCL-pins-list" class="pins-container"></div>
<p>Select SDA Pin: <span id="alt-SDA-pin"></span></p>
<div id="SDA-pins-list" class="pins-container"></div>
</div>
</div>
<div id="i2c-mux-container">
<div id="i2c-mux-container" class="dashed-section">
<h3>I2C Multiplexers (Optional)</h3>
<button id="add-mux-btn">Add I2C Multiplexer</button>
@ -341,9 +415,6 @@
<button class="comp-tab" onclick="openComponentTab(event, 'i2c-components')">I2C Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'ds18x20-components')">DS18x20 Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'pin-components')">Pin Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'pixel-components')">Pixel Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'pwm-components')">PWM Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'servo-components')">Servo Components</button>
<button class="comp-tab" onclick="openComponentTab(event, 'uart-components')">UART Components</button>
</div>
@ -362,12 +433,6 @@
<div class="search-filter">
<input type="text" id="i2c-search" class="component-search" placeholder="Search I2C components...">
</div>
<div>
<label for="i2c-bus-select">Select I2C Bus: </label>
<select id="i2c-bus-select">
<option value="default">Default I2C Bus</option>
</select>
</div>
<div class="component-list" id="i2c-component-list">
<!-- I2C components will be populated here -->
@ -445,6 +510,7 @@
<div id="generate-section" class="section hidden">
<h2>7. Generate Configuration</h2>
<button id="generate-config-btn">Generate Configuration</button>
<input type="checkbox" id="use-auto-init" onchange="javascript:appState.enableautoConfig=this.checked;"> <label for="use-auto-init" title="Auto config fallback for I2C sensors that fail to initialise (selects alternative sensors at same address)">Use Auto Init fallback for failed or unspecified components (default)</label>
<div id="config-output-container" class="hidden">
<h3>Configuration JSON:</h3>
<pre id="config-output" class="config-output"></pre>
@ -467,9 +533,10 @@
<textarea id="import-json" class="json-input" placeholder="Paste your configuration JSON here..."></textarea>
<button id="import-json-btn">Import from Text</button>
<div class="section">
<div class="section" style="visibility: hidden; height: 0px;">
<h2>Export Configuration</h2>
<p>Export the current configuration to a file:</p>
<textarea id="export-config" class="json-input hidden" placeholder="Exported configuration JSON will appear here and on the other page (when generate is clicked)..." ></textarea>
<button id="export-btn">Export Configuration</button>
</div>
@ -494,12 +561,12 @@
<input type="number" id="custom-board-analog" value="0" min="0" max="100">
</div>
<div>
<label for="custom-board-scl">Default I2C SCL Pin:</label>
<input type="text" id="custom-board-scl" placeholder="e.g. SCL, D3">
<label for="custom-board-SCL">Default I2C SCL Pin:</label>
<input type="text" id="custom-board-SCL" placeholder="e.g. SCL, D3">
</div>
<div>
<label for="custom-board-sda">Default I2C SDA Pin:</label>
<input type="text" id="custom-board-sda" placeholder="e.g. SDA, D2">
<label for="custom-board-SDA">Default I2C SDA Pin:</label>
<input type="text" id="custom-board-SDA" placeholder="e.g. SDA, D2">
</div>
<button id="add-custom-board-btn">Add Custom Board</button>
</div>
@ -527,6 +594,8 @@
</div>
</div>
</div>
<!-- Load release info -->
<script src="firmware-data.js"></script>
<!-- Load the data loader script -->
<script src="load-wippersnapper-data.js"></script>
@ -561,7 +630,7 @@
} else {
// If called programmatically, find and activate the correct tab
for (i = 0; i < tablinks.length; i++) {
if (tablinks[i].textContent.includes(tabName.replace('Export', 'Import/Export'))) {
if (tablinks[i].textContent.includes(tabName.replace(/(Export|Config)/, ''))) {
tablinks[i].className += " active";
}
}

View file

@ -1,8 +1,8 @@
// Load Wippersnapper boards and components data
// Configuration
const BOARDS_JSON_URL = 'https://raw.githubusercontent.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/main/wippersnapper_boards.json'; //'wippersnapper_boards.json';
const COMPONENTS_JSON_URL = 'https://raw.githubusercontent.com/tyeth/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/main/wippersnapper_components.json'; //'wippersnapper_components.json';
// Configuration - technically unused (instead ./ relative links) but useful for reference
const BOARDS_JSON_URL = 'https://raw.githubusercontent.com/adafruit/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/offline-mode/wippersnapper_boards.json'; //'wippersnapper_boards.json';
const COMPONENTS_JSON_URL = 'https://raw.githubusercontent.com/adafruit/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/offline-mode/wippersnapper_components.json'; //'wippersnapper_components.json';
// Global app state
const appState = {
@ -10,6 +10,7 @@ const appState = {
componentsData: null,
isLoading: false,
loadError: null,
enableautoConfig: false,
// Application state properties (from original code)
selectedBoard: null,
@ -47,6 +48,12 @@ async function loadWippersnapperData() {
await new Promise(resolve => setTimeout(resolve, 1000));
const boardsData = window['jsonBoardObject'];
const componentsData = window['jsonComponentsObject'];
const firmwareData = window['FIRMWARE_DATA'];
if (firmwareData && firmwareData.releaseInfo) {
document.getElementById('release_name').innerHTML = "(" + firmwareData.releaseInfo.publishedDate + ")<br/>" + firmwareData.releaseInfo.name;
document.getElementById('release_name').href = firmwareData.releaseInfo.url;
}
appState.boardsData = boardsData.boards;
appState.componentsData = componentsData.components;
document.body.removeChild(componentsObject);
@ -58,6 +65,10 @@ async function loadWippersnapperData() {
appState.componentsData.i2c.push({
id: 'pca9546',
name: 'PCA9546 I2C Multiplexer',
displayName: 'PCA9546 I2C Multiplexer',
productURL: 'https://www.adafruit.com/product/5664',
documentationURL: 'https://learn.adafruit.com/adafruit-pca9546-4-channel-stemma-qt-multiplexer',
image: 'https://cdn-shop.adafruit.com/640x480/5664-00.jpg',
address: '0x70',
addresses: ['0x70', '0x71', '0x72', '0x73', '0x74', '0x75', '0x76', '0x77'],
dataTypes: [],
@ -68,6 +79,10 @@ async function loadWippersnapperData() {
appState.componentsData.i2c.push({
id: 'pca9548',
name: 'PCA9548 I2C Multiplexer',
displayName: 'PCA9548 I2C Multiplexer',
productURL: 'https://www.adafruit.com/product/5626',
documentationURL: 'https://learn.adafruit.com/adafruit-pca9548-8-channel-stemma-qt-qwiic-i2c-multiplexer',
image: 'https://cdn-shop.adafruit.com/640x480/5626-06.jpg',
address: '0x70',
addresses: ['0x70', '0x71', '0x72', '0x73', '0x74', '0x75', '0x76', '0x77'],
dataTypes: [],
@ -78,6 +93,10 @@ async function loadWippersnapperData() {
appState.componentsData.i2c.push({
id: 'tca9546',
name: 'TCA9546 I2C Multiplexer',
displayName: 'TCA9546 4Ch I2C Multiplexer',
productURL: 'https://www.adafruit.com/product/5663',
documentationURL: 'https://learn.adafruit.com/adafruit-pca9546-4-channel-i2c-multiplexer',
image: 'https://cdn-shop.adafruit.com/640x480/5663-04.jpg',
address: '0x70',
addresses: ['0x70', '0x71', '0x72', '0x73', '0x74', '0x75', '0x76', '0x77'],
dataTypes: [],
@ -88,6 +107,10 @@ async function loadWippersnapperData() {
appState.componentsData.i2c.push({
id: 'tca9548',
name: 'TCA9548 I2C Multiplexer',
displayName: 'TCA9548 8Ch I2C Multiplexer',
productURL: 'https://www.adafruit.com/product/2717',
documentationURL: 'https://learn.adafruit.com/adafruit-tca9548a-1-to-8-i2c-multiplexer-breakout',
image: 'https://cdn-shop.adafruit.com/640x480/2717-00.jpg',
address: '0x70',
addresses: ['0x70', '0x71', '0x72', '0x73', '0x74', '0x75', '0x76', '0x77'],
dataTypes: [],
@ -136,16 +159,19 @@ function populateBoardSelect() {
// Filter boards to only include those with UF2 install method
const filteredBoards = Object.entries(appState.boardsData)
.filter(([boardId, board]) => ['uf2', 'web-native-usb'].includes(board.installMethod));
.filter(([boardId, board]) => ['uf2', 'web-native-usb'].includes(board.installMethod)); //funhouse
// Sort boards by vendor and name
const sortedBoards = filteredBoards
.sort((a, b) => {
const vendorA = a[1].vendor || '';
const vendorB = b[1].vendor || '';
if (vendorA === 'Generic') {
return 1; // Sort Generic to the end
} else if (vendorB === 'Generic') {
return -1; // Sort Generic to the end
} else if (vendorA !== vendorB) {
// Sort by vendor first
if (vendorA !== vendorB) {
return vendorA.localeCompare(vendorB);
}
@ -191,19 +217,14 @@ function convertBoardDataToConfig(boardId) {
// Extract pin numbers from board data
const pins = boardData.pins.map(pin => pin.number).filter(num => !isNaN(num));
boardConfig = boardData;
// Create board config
const boardConfig = {
referenceVoltage: boardData.referenceVoltage,
totalGPIOPins: boardData.totalGPIOPins,
totalAnalogPins: boardData.totalAnalogPins || 0,
defaultI2C: {
scl: boardData.defaultI2C.SCL,
sda: boardData.defaultI2C.SDA
},
pins: pins,
displayName: boardData.displayName,
image: boardData.image
boardConfig.totalAnalogPins= boardData.totalAnalogPins || 0;
boardConfig.defaultI2C= {
SCL: boardData.defaultI2C.SCL,
SDA: boardData.defaultI2C.SDA
};
boardConfig.pins= pins;
return boardConfig;
}
@ -229,6 +250,7 @@ function convertComponentsDataToConfig() {
componentsConfig.i2c.push({
id: component.id,
name: component.name,
displayName: component.displayName || component.name,
address: component.address || '0x00',
addresses: component.addresses || [component.address || '0x00'],
dataTypes: component.dataTypes || [],
@ -242,6 +264,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.ds18x20.forEach(component => {
componentsConfig.ds18x20.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -253,6 +276,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.pin.forEach(component => {
componentsConfig.pin.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -264,6 +288,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.pixel.forEach(component => {
componentsConfig.pixel.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -275,6 +300,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.pwm.forEach(component => {
componentsConfig.pwm.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -286,6 +312,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.servo.forEach(component => {
componentsConfig.servo.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -297,6 +324,7 @@ function convertComponentsDataToConfig() {
appState.componentsData.uart.forEach(component => {
componentsConfig.uart.push({
id: component.id,
displayName: component.displayName || component.name,
name: component.name,
dataTypes: component.dataTypes || []
});
@ -310,81 +338,21 @@ function convertComponentsDataToConfig() {
* Attach event listeners to the UI elements
*/
function attachEventListeners() {
// Board selection handler
document.getElementById('board-select').addEventListener('change', function() {
const boardId = this.value;
if (!boardId) {
document.getElementById('board-details').classList.add('hidden');
hideSubsequentSections();
return;
}
// BOARD SELECTION HANDLER HAS BEEN REMOVED
// The duplicate event handler from load-wippersnapper-data.js has been removed
// to prevent conflicts with the handler in wippersnapper-config-builder.js
// Convert board data to config format
const boardConfig = convertBoardDataToConfig(boardId);
appState.selectedBoard = {
id: boardId,
...boardConfig
};
// Update board details display
document.getElementById('ref-voltage').textContent = boardConfig.referenceVoltage;
document.getElementById('total-gpio').textContent = boardConfig.totalGPIOPins;
document.getElementById('total-analog').textContent = boardConfig.totalAnalogPins;
document.getElementById('default-scl').textContent = boardConfig.defaultI2C.scl;
document.getElementById('default-sda').textContent = boardConfig.defaultI2C.sda;
document.getElementById('board-details').classList.remove('hidden');
// If there's a board image, show it
const boardImageElem = document.getElementById('board-image');
if (boardImageElem) {
if (boardConfig.image) {
if (!boardConfig.image.startsWith('http')) {
boardImageElem.src = "https://raw.githubusercontent.com/adafruit/Wippersnapper_Boards/refs/heads/main/" + boardConfig.image;
} else {
boardImageElem.src = boardConfig.image;
}
boardImageElem.classList.remove('hidden');
} else {
boardImageElem.classList.add('hidden');
}
}
// Set up default I2C bus
appState.i2cBuses = [{
id: 'default',
scl: boardConfig.defaultI2C.scl,
sda: boardConfig.defaultI2C.sda
}];
// Update default I2C bus display
document.getElementById('default-i2c-scl').textContent = boardConfig.defaultI2C.scl;
document.getElementById('default-i2c-sda').textContent = boardConfig.defaultI2C.sda;
// Mark default I2C pins as used
appState.usedPins.add(boardConfig.defaultI2C.scl);
appState.usedPins.add(boardConfig.defaultI2C.sda);
// Show companion board section
document.getElementById('companion-board-section').classList.remove('hidden');
// Reset subsequent sections
resetSubsequentSelections();
// Initialize SD and RTC sections based on board
initializeManualConfig();
// Initialize pins lists for SD and I2C configuration
populatePinsLists();
// Instead, we'll prepare the data in the format expected by wippersnapper-config-builder.js
console.log('Data loading complete, board selection handler is in wippersnapper-config-builder.js');
// Convert component data to config format
const componentsConfig = convertComponentsDataToConfig();
console.log('not using Components data converted to config format:', componentsConfig);
// Update the components data in appState with the converted format
// so it's ready for use in the other script
// appState.componentsData = componentsConfig;
// Initialize components sections with the loaded data
populateComponentLists(componentsConfig);
});
// Remaining event listeners should be added here or in the original script
// ...
// No other event listeners needed here as they are handled in wippersnapper-config-builder.js
}
/**

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
requests

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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff