Compare commits

..

2 commits

Author SHA1 Message Date
tyeth
679848a9ff Mention GPS custom datatype/sensortype insertion points 2025-07-31 12:24:08 +01:00
tyeth
70cb0120a0 Update for web-native-usb (not just uf2) 2025-07-30 22:12:38 +01:00
14 changed files with 8669 additions and 10769 deletions

View file

@ -42,9 +42,9 @@ jobs:
git submodule init
git submodule update --recursive
cd Wippersnapper_Boards
git reset --hard origin/offline-mode
git reset --hard origin/rp2040_datalogger_feather
cd ../Wippersnapper_Components
git reset --hard origin/offline-mode
git reset --hard origin/main
cd ..
git add Wippersnapper_Boards Wippersnapper_Components
git diff --staged --quiet || git commit -m "Update submodules to latest versions [skip ci]"

3
.gitignore vendored
View file

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

1
.gitmodules vendored
View file

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

@ -1 +1 @@
Subproject commit 941e94a52bbe1f33aed3328ddd0ec7a5f3adfbd0
Subproject commit 66d399578444320a039514f1a41160a0c2357212

@ -1 +1 @@
Subproject commit dc7f57cb1697e4efc4e9490cc51b7ec569f32c15
Subproject commit 1f7823e15ee49acffb15aab2cc947ea7d1ad6619

View file

@ -156,70 +156,7 @@ def convert_components_to_json():
component_info["channels"] = 8
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
@ -270,12 +207,12 @@ def convert_components_to_json():
# Write the consolidated JSON file
with open(OUTPUT_FILE, 'w') as f:
json.dump({"components": components}, f, ensure_ascii=False, indent=2)
json.dump({"components": components}, f, 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, ensure_ascii=False, indent=2)
json.dump({"components": components}, f, indent=2)
f.write(";\n")
print(f"Successfully created {OUTPUT_FILE}")

View file

@ -1,155 +1,139 @@
// Auto-generated on 2025-08-29 00:19:42
// Auto-generated on 2025-07-30 00:22:35
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"
"version": "1.0.0-offline-beta.3",
"name": "WipperSnapper Offline 1.0.0-offline-beta.3",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/tag/1.0.0-offline-beta.3",
"publishedDate": "2025-05-13"
},
"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,
"name": "wippersnapper.feather_esp32s2.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s2.1.0.0-offline-beta.3.uf2",
"size": 2779136,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s2_reverse_tft.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s2_reverse_tft.1.0.0-offline-beta.3.uf2",
"size": 2779136,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s2_tft.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s2_tft.1.0.0-offline-beta.3.uf2",
"size": 2778624,
"downloadCount": 2,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s3.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s3.1.0.0-offline-beta.3.uf2",
"size": 2836480,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s3_4mbflash_2mbpsram.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s3_4mbflash_2mbpsram.1.0.0-offline-beta.3.uf2",
"size": 2842112,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s3_reverse_tft.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s3_reverse_tft.1.0.0-offline-beta.3.uf2",
"size": 2842112,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_esp32s3_tft.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_esp32s3_tft.1.0.0-offline-beta.3.uf2",
"size": 2842112,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.feather_rp2040_adalogger_tinyusb.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.feather_rp2040_adalogger_tinyusb.1.0.0-offline-beta.3.uf2",
"size": 669696,
"downloadCount": 8,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.metroesp32s2.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.metroesp32s2.1.0.0-offline-beta.3.uf2",
"size": 2778624,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.metro_esp32s3.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.metro_esp32s3.1.0.0-offline-beta.3.uf2",
"size": 2846208,
"downloadCount": 0,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.metro_rp2350_tinyusb.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.metro_rp2350_tinyusb.1.0.0-offline-beta.3.uf2",
"size": 674304,
"downloadCount": 2,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.pico_rp2040_tinyusb.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.pico_rp2040_tinyusb.1.0.0-offline-beta.3.uf2",
"size": 667648,
"downloadCount": 2,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.pico_rp2350_tinyusb.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.pico_rp2350_tinyusb.1.0.0-offline-beta.3.uf2",
"size": 659456,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.qtpy_esp32s2.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.qtpy_esp32s2.1.0.0-offline-beta.3.uf2",
"size": 2778624,
"downloadCount": 3,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.qtpy_esp32s3.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.qtpy_esp32s3.1.0.0-offline-beta.3.uf2",
"size": 2836480,
"downloadCount": 1,
"contentType": "application/octet-stream",
"createdAt": "2025-08-18T17:38:47Z"
"createdAt": "2025-05-13T17:26:26Z"
},
{
"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,
"name": "wippersnapper.qtpy_esp32s3_n4r2.1.0.0-offline-beta.3.uf2",
"url": "https://github.com/adafruit/Adafruit_Wippersnapper_Arduino/releases/download/1.0.0-offline-beta.3/wippersnapper.qtpy_esp32s3_n4r2.1.0.0-offline-beta.3.uf2",
"size": 2842112,
"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"
"createdAt": "2025-05-13T17:26:26Z"
}
]
};

View file

@ -314,8 +314,7 @@
<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">
@ -359,7 +358,6 @@
<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>
@ -409,13 +407,17 @@
<div id="components-section" class="section hidden">
<h2>5. Add Components</h2>
<p style="color: red;"><small><i>UART + other component categories are currently being implemented in offline mode (No ETA, but maybe reactive actions too!).</i></small></p>
<div id="component-type-tabs" class="tab">
<button class="comp-tab active" onclick="openComponentTab(event, 'all-components')">All Components</button>
<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, 'uart-components')">UART Components</button>
<button class="comp-tab not-available-yet" onclick="openComponentTab(event, 'pixel-components')">Pixel Components</button>
<button class="comp-tab not-available-yet" onclick="openComponentTab(event, 'pwm-components')">PWM Components</button>
<button class="comp-tab not-available-yet" onclick="openComponentTab(event, 'servo-components')">Servo Components</button>
<button class="comp-tab not-available-yet" onclick="openComponentTab(event, 'uart-components')">UART Components</button>
</div>
<div id="all-components" class="component-tabcontent" style="display: block;">
@ -510,7 +512,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>
<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</label>
<div id="config-output-container" class="hidden">
<h3>Configuration JSON:</h3>
<pre id="config-output" class="config-output"></pre>

View file

@ -1,8 +1,8 @@
// Load Wippersnapper boards and components data
// 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';
const BOARDS_JSON_URL = 'https://raw.githubusercontent.com/adafruit/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/main/wippersnapper_boards.json'; //'wippersnapper_boards.json';
const COMPONENTS_JSON_URL = 'https://raw.githubusercontent.com/adafruit/Adafruit_Wippersnapper_Offline_Configurator/refs/heads/main/wippersnapper_components.json'; //'wippersnapper_components.json';
// Global app state
const appState = {

View file

@ -126,22 +126,6 @@ const companionBoardConfigs = {
productURL: 'https://www.adafruit.com/product/4285',
documentationURL: 'https://learn.adafruit.com/adafruit-airlift-shield-esp32-wifi-co-processor',
image: 'https://cdn-shop.adafruit.com/640x480/4285-05.jpg'
},
'seeed-xiao-s3sense-camera-addon': {
rtc: null,
sdCardCS: 21,
extras: 'SD Card, Camera, Microphone, Extra GPIOs D11+D12',
productURL: 'https://www.seeedstudio.com/XIAO-ESP32S3-Sense-p-5639.html',
documentationURL: 'https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/',
image: 'https://files.seeedstudio.com/wiki/SeeedStudio-XIAO-ESP32S3/img/66.jpg'
},
'seeed-xiao-ssd1306-expansion-base': {
rtc: 'PCF8563',
sdCardCS: 'D2',
extras: 'SD Card, Display, Piezo Speaker, LiPo connector',
productURL: 'https://www.seeedstudio.com/Seeeduino-XIAO-Expansion-board-p-4746.html',
documentationURL: 'https://wiki.seeedstudio.com/Seeeduino-XIAO-Expansion-Board/',
image: 'https://files.seeedstudio.com/wiki/Seeeduino-XIAO-Expansion-Board/Update_pic/zheng1.jpg'
}
};
@ -381,7 +365,7 @@ document.addEventListener('DOMContentLoaded', function() {
// Mark SD CS pin as used
appState.usedPins.add(pin.number);
} else {
console.warn(`[${companionId}] SD card CS pin ${companion.sdCardCS} not found in selected board pins.`);
console.warn(`SD card CS pin ${companion.sdCardCS} not found in selected board pins.`);
document.getElementById('sd-missing').classList.remove('hidden');
document.getElementById('sd-present').classList.add('hidden');
}
@ -453,12 +437,8 @@ document.addEventListener('DOMContentLoaded', function() {
document.getElementById('sd-card-pin-select').classList.remove('hidden');
} else {
document.getElementById('sd-card-pin-select').classList.add('hidden');
appState.usedPins.delete(appState.sdCardCS);
document.getElementById('manual-sd-cs-pin').textContent = '';
document.getElementById('sd-cs-pin').textContent = '';
appState.sdCardCS = null;
}
populatePinsLists();
});
// RTC type selection handler
@ -1028,7 +1008,7 @@ function createComponentCard(component, type) {
if (component.image) {
const img = document.createElement('img');
if (!component.image.startsWith('http')) {
img.src = "https://raw.githubusercontent.com/adafruit/Wippersnapper_Components/refs/heads/offline-mode/" + component.image;
img.src = "https://raw.githubusercontent.com/adafruit/Wippersnapper_Components/refs/heads/main/" + component.image;
} else {
img.src = component.image;
}
@ -1335,6 +1315,8 @@ function showComponentConfigModal(component, type) {
</select>
</div>
`;
// TODO: Tyeth/Brent - Add GPS properties here if needed, or below in datatypes
}
// Data type selection
@ -1543,15 +1525,9 @@ function saveModalData() {
const componentConfig = {
instanceId: appState.nextComponentId++,
name: name,
componentAPI: componentType == 'pin' ? componentTemplate.componentAPI : componentType
componentAPI: componentType == 'pin' ? componentTemplate.componentAPI : componentType,
period: period
};
// Only add period for components that don't have their own period objects
if (! componentTemplate.deviceType !== 'gps' &&
componentTemplate.deviceType !== 'pm25aqi' &&
componentTemplate.deviceType !== 'generic_input') {
componentConfig.period = period;
}
let validationError = false; // future use
// Special handling for I2C
@ -1562,24 +1538,6 @@ function saveModalData() {
componentConfig.i2cDeviceName = componentId;
componentConfig.i2cDeviceAddress = i2cAddress;
// Add GPS fields if they exist in the component template
if (componentTemplate.isGps) {
componentConfig.isGps = componentTemplate.isGps;
// Add gps object with period (convert from seconds to milliseconds)
if (!componentConfig.gps) {
componentConfig.gps = {};
}
componentConfig.gps.period = period;
if (componentTemplate.gps.commands_ubxes) {
componentConfig.gps.commands_ubxes = componentTemplate.gps.commands_ubxes;
}
if (componentTemplate.gps.commands_pmtks) {
componentConfig.gps.commands_pmtks = componentTemplate.gps.commands_pmtks;
}
}
// Handle multiplexer channel if selected
if (i2cBus.startsWith('mux-')) {
const [_, muxId, __, channelNum] = i2cBus.split('-');
@ -1623,22 +1581,20 @@ function saveModalData() {
appState.selectedComponents = appState.selectedComponents.filter(c =>
!(c.i2cMuxAddress && c.i2cMuxAddress === componentConfig.i2cDeviceAddress));
} else {
if (! componentTemplate.isGps) {
// Add data types for non-multiplexer components
const dataTypeCheckboxes = document.querySelectorAll('input[name="data-type"]:checked');
if (dataTypeCheckboxes.length > 0) {
componentConfig.i2cDeviceSensorTypes = Array.from(dataTypeCheckboxes).map(checkbox => {
try {
return { type: JSON.parse(checkbox.value) };
} catch (e) {
return { type: checkbox.value };
}
});
} else {
validationError = true;
alert('Please select at least one data type for the I2C component.');
return false;
}
// Add data types for non-multiplexer components
const dataTypeCheckboxes = document.querySelectorAll('input[name="data-type"]:checked');
if (dataTypeCheckboxes.length > 0) {
componentConfig.i2cDeviceSensorTypes = Array.from(dataTypeCheckboxes).map(checkbox => {
try {
return { type: JSON.parse(checkbox.value) };
} catch (e) {
return { type: checkbox.value };
}
});
} else {
validationError = true;
alert('Please select at least one data type for the I2C component.');
return false;
}
}
} else if (componentType === 'ds18x20') {
@ -1696,75 +1652,31 @@ function saveModalData() {
// Mark pin as used
appState.usedPins.add(parseInt(pin));
} else if (componentType === 'uart') {
const pinTx = document.getElementById('modal-uart-tx').value;
const pinRx = document.getElementById('modal-uart-rx').value;
if (!pinRx) {
const txPin = document.getElementById('modal-uart-tx').value;
const rxPin = document.getElementById('modal-uart-rx').value;
if (!rxPin) {
validationError = true;
alert('Please select a RX pin for the component.');
return false;
}
if (!!pinTx) {
componentConfig.pinTx = `D${pinTx}`;
appState.usedPins.add(parseInt(pinTx));
if (!!txPin) {
componentConfig.txPin = `D${txPin}`;
appState.usedPins.add(parseInt(txPin));
}
componentConfig.pinRx = `D${pinRx}`;
appState.usedPins.add(parseInt(pinRx));
componentConfig.rxPin = `D${rxPin}`;
appState.usedPins.add(parseInt(rxPin));
// Add data types
const dataTypeCheckboxes = document.querySelectorAll('input[name="data-type"]:checked');
if (dataTypeCheckboxes.length > 0) {
componentConfig.sensorTypes = Array.from(dataTypeCheckboxes).map(checkbox => {
try {
return { type: JSON.parse(checkbox.value) };
return JSON.parse(checkbox.value);
} catch (e) {
return { type: checkbox.value };
return checkbox.value;
}
});
}
// UART-Specific //
// Add deviceType field if it exists in the component template
if (componentTemplate.deviceType) {
componentConfig.deviceType = componentTemplate.deviceType;
}
// Add deviceId field if it exists in the component template
if (componentTemplate.deviceId) {
componentConfig.deviceId = componentTemplate.deviceId;
}
// Add GPS fields if this is a GPS component
if (componentTemplate.deviceType === 'gps') {
if (!componentConfig.gps) {
componentConfig.gps = {};
}
componentConfig.gps.period = period;
if (componentTemplate.gps.commands_ubxes) {
componentConfig.gps.commands_ubxes = componentTemplate.gps.commands_ubxes;
}
if (componentTemplate.gps.commands_pmtks) {
componentConfig.gps.commands_pmtks = componentTemplate.gps.commands_pmtks;
}
}
// Add PM25AQI fields if this is a PM25AQI component
if (componentTemplate.deviceType === 'pm25aqi') {
if (!componentConfig.pm25aqi) {
componentConfig.pm25aqi = {};
}
componentConfig.pm25aqi.period = period;
}
// Add generic_input fields if this is a generic_input component
if (componentTemplate.deviceType === 'generic_input') {
if (!componentConfig.generic_input) {
componentConfig.generic_input = {};
}
componentConfig.generic_input.period = period;
}
}
// Add component to the selected components list
@ -1848,7 +1760,9 @@ function updateSelectedComponentsList() {
detailsText += `<br>Pin: ${component.pinName}`;
detailsText += `<br>Pixels: ${component.numPixels}`;
} else if (component.componentAPI === 'uart') {
detailsText += `<br>TX Pin: ${component.pinTx}, RX Pin: ${component.pinRx}`;
detailsText += `<br>TX Pin: ${component.txPin}, RX Pin: ${component.rxPin}`;
// TODO: Tyeth/Brent - Add GPS properties here if needed, or override sensorTypes
// Show sensor types
if (component.sensorTypes && component.sensorTypes.length > 0) {
@ -1900,14 +1814,14 @@ function removeComponent(instanceId) {
appState.usedPins.delete(pinNumber);
}
if (component.pinTx) {
const pinTxNumber = parseInt(component.pinTx.replace('D', ''));
appState.usedPins.delete(pinTxNumber);
if (component.txPin) {
const txPinNumber = parseInt(component.txPin.replace('D', ''));
appState.usedPins.delete(txPinNumber);
}
if (component.pinRx) {
const pinRxNumber = parseInt(component.pinRx.replace('D', ''));
appState.usedPins.delete(pinRxNumber);
if (component.rxPin) {
const rxPinNumber = parseInt(component.rxPin.replace('D', ''));
appState.usedPins.delete(rxPinNumber);
}
// Check if this is a multiplexer and remove it from the multiplexers list
@ -1960,8 +1874,7 @@ function generateConfiguration() {
referenceVoltage: appState.selectedBoard.referenceVoltage,
totalGPIOPins: appState.selectedBoard.totalGPIOPins,
totalAnalogPins: appState.selectedBoard.totalAnalogPins,
statusLEDBrightness: appState.statusLEDBrightness,
autoConfig: appState.enableautoConfig
statusLEDBrightness: appState.statusLEDBrightness
},
components: []
};
@ -2381,14 +2294,14 @@ function importConfigObject(config) {
appState.usedPins.add(pinNumber);
}
if (component.pinTx) {
const pinTxNumber = parseInt(component.pinTx.replace('D', ''));
appState.usedPins.add(pinTxNumber);
if (component.txPin) {
const txPinNumber = parseInt(component.txPin.replace('D', ''));
appState.usedPins.add(txPinNumber);
}
if (component.pinRx) {
const pinRxNumber = parseInt(component.pinRx.replace('D', ''));
appState.usedPins.add(pinRxNumber);
if (component.rxPin) {
const rxPinNumber = parseInt(component.rxPin.replace('D', ''));
appState.usedPins.add(rxPinNumber);
}
// Handle I2C bus pins

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