Merge branch 'adafruit:main' into main

This commit is contained in:
BrainBoardz 2023-03-20 16:29:15 -04:00 committed by GitHub
commit a8a19d4bbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 36749 additions and 3784 deletions

View file

@ -29,13 +29,13 @@ jobs:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Set up Python 3.x
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Versions
run: |
python3 --version
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: true
- name: Install deps

View file

@ -27,19 +27,19 @@ jobs:
# be limited (they run on all forks' default branches).
if: startswith(github.repository, 'adafruit/')
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: true
- name: Update Awesome CircuitPython
run: |
(cd awesome-circuitpython && git fetch origin main:main && git checkout main)
- name: Set up Python 3.x
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.x
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.1'
ruby-version: '3'
bundler-cache: true
- name: Install Dependencies
run: |
@ -50,6 +50,18 @@ jobs:
run: python3 check-boards.py
- name: Check Image Dimensions
run: python3 check-images.py
- name: Make Directory For Report Files
run: mkdir -p json
- name: Generate ESP32 Boards JSON
run: python3 generate-board-info.py -o json/esp32_boards.json
- name: Check For Files
run: |
ls json
- name: Upload ESP32 Boards JSON To AWS S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: "[ -z \"$AWS_ACCESS_KEY_ID\" ] || aws s3 cp json/esp32_boards.json s3://adafruit-circuit-python/esp32_boards.json --no-progress --region us-east-1"
- name: Build site with jekyll
run: |
bundle exec jekyll build -d build

View file

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Compress Images
uses: calibreapp/image-actions@main

View file

@ -4,7 +4,7 @@ GEM
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
colorator (1.1.0)
concurrent-ruby (1.1.10)
concurrent-ruby (1.2.2)
deep_merge (1.2.2)
em-websocket (0.5.3)
eventmachine (>= 0.12.9)
@ -12,15 +12,15 @@ GEM
eventmachine (1.2.7)
ffi (1.15.5)
forwardable-extended (2.6.0)
google-protobuf (3.21.12)
google-protobuf (3.21.12-x86_64-linux)
google-protobuf (3.22.0)
google-protobuf (3.22.0-x86_64-linux)
http_parser.rb (0.8.0)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
jekyll (4.3.1)
jekyll (4.3.2)
addressable (~> 2.4)
colorator (~> 1.0)
em-websocket (~> 0.5)
@ -68,17 +68,17 @@ GEM
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rouge (4.0.1)
rouge (4.1.0)
ruby-vips (2.1.4)
ffi (~> 1.12)
safe_yaml (1.0.5)
sass-embedded (1.54.6)
google-protobuf (~> 3.19)
sass-embedded (1.58.3)
google-protobuf (~> 3.21)
rake (>= 10.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
unicode-display_width (2.4.2)
webrick (1.7.0)
webrick (1.8.1)
PLATFORMS
ruby

View file

@ -36,5 +36,5 @@ Seeed Studio XIAO nRF52840 (Sense) contains a wealthy interface. The first thing
* built-in 2 MB flash, microphone and 6-axis IMU
## Purchase
* [Seeed Studio] SENSE version (https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html)
* [Seeed Studio] version without sensor (https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
* [Seeed Studio](https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html) SENSE version
* [Seeed Studio](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html) version without sensor

View file

@ -20,7 +20,7 @@ features:
What's Feather-shaped and has an ESP32-S2 WiFi module? What has a STEMMA QT connector for I2C devices? What has your favorite Espressif WiFi microcontroller and lots of Flash and RAM memory for your next IoT project? What will make your next IoT project flyyyyy?
That's right - it's the new **Adafruit Feather ESP32-S2** and the **Adafruit Feather ESP32-S2 with BME280**! With native USB and 4 MB flash + 2 MB of PSRAM, this board is perfect for use with CircuitPython or Arduino with low-cost WiFi. Native USB means it can act like a keyboard or a disk drive. WiFi means its awesome for IoT projects. And Feather means it works with the large community of Feather Wings for expandability.
That's right - it's the new **Adafruit Feather ESP32-S2**! With native USB and 4 MB flash + 2 MB of PSRAM, this board is perfect for use with CircuitPython or Arduino with low-cost WiFi. Native USB means it can act like a keyboard or a disk drive. WiFi means its awesome for IoT projects. And Feather means it works with the large community of Feather Wings for expandability.
The ESP32-S2 is a highly-integrated, low-power, 2.4 GHz Wi-Fi System-on-Chip (SoC) solution that now has **built-in native USB** as well as some other interesting new technologies like Time of Flight distance measurements. With its state-of-the-art power and RF performance, this SoC is an ideal choice for a wide variety of application scenarios relating to the [Internet of Things (IoT)](https://www.adafruit.com/category/342), [wearable electronics](https://www.adafruit.com/category/65), and smart homes.
@ -32,7 +32,6 @@ The ESP32-S2 is a highly-integrated, low-power, 2.4 GHz Wi-Fi System-on-Chip (So
- **Mini module** has FCC/CE certification and comes with 4 MB of Flash and 2 M of PSRAM - you can have huge data buffers
- **Power options** - USB-C **or** Lipoly battery
- **Built-in battery charging** when powered over USB-C
- **BME280** temperature / humidity / barometric pressure sensor connected over I2C on address `0x77` for immediate ambient weather sensing (**on BME280 version only!**)
- **LiPoly battery monitor** - LC709203 chip actively monitors your battery for voltage and state of charge / percentage reporting over I2C
- **Reset and DFU** (BOOT0) buttons to get into the ROM bootloader (which is a USB serial port so you don't need a separate cable!)
- **Serial debug output pin** (optional, for checking the hardware serial debug console)

View file

@ -5,7 +5,7 @@ title: "ESP32-S3 Reverse TFT Feather Download"
name: "ESP32-S3 Reverse TFT Feather"
manufacturer: "Adafruit"
board_url: ""
board_image: "adafruit_feather_esp32s2_reverse_tft.jpg"
board_image: "adafruit_feather_esp32s3_reverse_tft.jpg"
date_added: 2023-1-31
family: esp32s3
bootloader_id: adafruit_feather_esp32s3_reverse_tft
@ -21,5 +21,31 @@ features:
- Display
---
Coming Soon. Image is of the S2 version, but will be updated.
Like Missy Elliot, we like to ["put our [Feather\] down, flip it and reverse it"](https://www.youtube.com/watch?v=cjIvu7e6Wq8) and that's exactly what we've done with this new development board. It's basically our **[ESP32-S3 TFT Feather](https://www.adafruit.com/product/5483)** but with the 240x135 color TFT display on the back-side not the front-side. That makes it great for panel-mounted projects, particularly since we've also got some space for 3 buttons to go along. It's like an all-in-one display interface dev board, powered by the fantastic ESP32-S3 WIFI module.
This Feather comes with native USB and **4 MB Flash + 2 MB of PSRAM**, so it is perfect for use with CircuitPython or Arduino with low-cost WiFi. Native USB means it can act like a keyboard or a disk drive. WiFi means it's awesome for IoT projects. And Feather means it works with the large community of Feather Wings for expandability.
The ESP32-S3 is a highly-integrated, low-power, 2.4 GHz Wi-Fi/BLE System-on-Chip (SoC) solution that has built-in native USB as well as some other interesting new technologies like Time of Flight distance measurements and AI acceleration. With its state-of-the-art power and RF performance, this SoC is an ideal choice for a wide variety of application scenarios relating to the [Internet of Things (IoT)](https://www.adafruit.com/category/342), [wearable electronics](https://www.adafruit.com/category/65), and smart homes.
The Feather ESP32-S3 has a dual-core 240 MHz chip, so it is comparable to ESP32's dual-core. However, there is no Bluetooth **Classic** support, only Bluetooth LE. This chip is a great step up from the earlier ESP32-S2! This ESP32-S3 mini-module we are using on the Feather comes with 4 MB flash and 2 MB PSRAM, as well as lots of 512KB of SRAM so it's perfect for use with CircuitPython support or any time massive buffers are needed: for fast memory access use SRAM, for slower-but-roomier access use PSRAM. It's also great for use in ESP-IDF or with Arduino support.
The color TFT is connected to the SPI pins and uses additional pins for control that are not exposed to the breakout pads. [It's the same display as you see here, with 240x135 pixels and is IPS](https://www.adafruit.com/product/4383) so you get bright color at any angle. The backlight is also connected to a separate pin so you can PWM the backlight up and down as desired.
For low power usages, the Feather has a *second* low-dropout 3.3V regulator. The regulator is controlled with a GPIO pin on the enable line and can shut off power to the Stemma QT port and TFT. There is also a separate power pin for the NeoPixel that can be used to disable it for even lower quiescent power. With everything off and in deep sleep mode, the TFT feather uses about 100uA of current.
**Features:**
- **ESP32-S3 Dual Core 240MHz Tensilica processor** - the next generation of ESP32-Sx, with native USB so it can act like a keyboard/mouse, MIDI device, disk drive, etc!
- **Mini module** has FCC/CE certification and comes with 4 MByte of Flash and 2 MByte of PSRAM - you can have huge data buffers
- **[Color 1.14" IPS TFT with 240x135 pixels](https://www.adafruit.com/product/4383)** - bright and colorful display with ST7789 chipset that can be viewed at any angle angle.
- **Three User Tactile buttons** - D0, D1, and D2. D0/BOOT0 is also used for entering ROM bootloader mode if necessary.
- **Power options** - USB type C **or** Lipoly battery
- **Built-in battery charging** when powered over USB-C
- **LiPoly battery monitor** - MAX17048 chip actively monitors your battery for voltage and state of charge / percentage reporting over I2C
- **Reset and DFU** (BOOT0) buttons to get into the ROM bootloader (which is a USB serial port so you don't need a separate cable!)
- **Serial debug output pin** (optional, for checking the hardware serial debug console)
- **STEMMA QT** connector for I2C devices, with switchable power, so you can go into low power mode.
- **On/Charge/User** LEDs + status **NeoPixel** with pin-controlled power for low power usage
- **Low Power friendly**! In deep sleep mode, we can get down to 40~50uA of current draw from the Lipoly connection. Quiescent current is from the power regulator, ESP32-S2 chip, and Lipoly monitor. Turn off the NeoPixel and external I2C/TFT power for the lowest quiescent current draw.
- **Works with Arduino or CircuitPython**

View file

@ -20,32 +20,32 @@ features:
- Breadboard-Friendly
---
- We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want your very own soft serve ice cream machine? OK well, that's not something we can provide. But we can provide your *second*-deepest desire: an **ESP32-S*3* Feather board with a built in IPS TFT color display**. It's got all the delicious creamy goodness features of a Feather main board, the comforting warmth of an ESP32-S3 WiFi+BLE microcontroller, and the crispness of a 240x135 pixel color TFT display. All that and it will even plug in nicely into a breadboard, [terminal block wing](https://www.adafruit.com/product/2926), or [Feather Doubler](https://www.adafruit.com/product/2890) or even just stack on top of another wing.
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want your very own soft serve ice cream machine? OK well, that's not something we can provide. But we can provide your *second*-deepest desire: an **ESP32-S*3* Feather board with a built in IPS TFT color display**. It's got all the delicious creamy goodness features of a Feather main board, the comforting warmth of an ESP32-S3 WiFi+BLE microcontroller, and the crispness of a 240x135 pixel color TFT display. All that and it will even plug in nicely into a breadboard, [terminal block wing](https://www.adafruit.com/product/2926), or [Feather Doubler](https://www.adafruit.com/product/2890) or even just stack on top of another wing.
This Feather comes with native USB and **4 MB Flash + 2 MB of PSRAM**, so it is perfect for use with CircuitPython or Arduino with low-cost WiFi. Native USB means it can act like a keyboard or a disk drive. WiFi means it's awesome for IoT projects. And Feather means it works with the large community of Feather Wings for expandability.
This Feather comes with native USB and **4 MB Flash + 2 MB of PSRAM**, so it is perfect for use with CircuitPython or Arduino with low-cost WiFi. Native USB means it can act like a keyboard or a disk drive. WiFi means it's awesome for IoT projects. And Feather means it works with the large community of Feather Wings for expandability.
The ESP32-S3 is a highly-integrated, low-power, 2.4 GHz Wi-Fi/BLE System-on-Chip (SoC) solution that has built-in native USB as well as some other interesting new technologies like Time of Flight distance measurements and AI acceleration. With its state-of-the-art power and RF performance, this SoC is an ideal choice for a wide variety of application scenarios relating to the [Internet of Things (IoT)](https://www.adafruit.com/category/342), [wearable electronics](https://www.adafruit.com/category/65), and smart homes.
The ESP32-S3 is a highly-integrated, low-power, 2.4 GHz Wi-Fi/BLE System-on-Chip (SoC) solution that has built-in native USB as well as some other interesting new technologies like Time of Flight distance measurements and AI acceleration. With its state-of-the-art power and RF performance, this SoC is an ideal choice for a wide variety of application scenarios relating to the [Internet of Things (IoT)](https://www.adafruit.com/category/342), [wearable electronics](https://www.adafruit.com/category/65), and smart homes.
The Feather ESP32-S3 has a dual-core 240 MHz chip, so it is comparable to ESP32's dual-core. However, there is no Bluetooth **Classic** support, only Bluetooth LE. This chip is a great step up from the earlier ESP32-S2! This ESP32-S3 mini-module we are using on the Feather comes with 4 MB flash and 2 MB PSRAM, as well as lots of 512KB of SRAM so it's perfect for use with CircuitPython support or any time massive buffers are needed: for fast memory access use SRAM, for slower-but-roomier access use PSRAM. It's also great for use in ESP-IDF or with Arduino support.
The Feather ESP32-S3 has a dual-core 240 MHz chip, so it is comparable to ESP32's dual-core. However, there is no Bluetooth **Classic** support, only Bluetooth LE. This chip is a great step up from the earlier ESP32-S2! This ESP32-S3 mini-module we are using on the Feather comes with 4 MB flash and 2 MB PSRAM, as well as lots of 512KB of SRAM so it's perfect for use with CircuitPython support or any time massive buffers are needed: for fast memory access use SRAM, for slower-but-roomier access use PSRAM. It's also great for use in ESP-IDF or with Arduino support.
The color TFT is connected to the SPI pins and uses additional pins for control that are not exposed to the breakout pads. [It's the same display as you see here, with 240x135 pixels and is IPS](https://www.adafruit.com/product/4383) so you get bright color at any angle. The backlight is also connected to a separate pin so you can PWM the backlight up and down as desired.
The color TFT is connected to the SPI pins and uses additional pins for control that are not exposed to the breakout pads. [It's the same display as you see here, with 240x135 pixels and is IPS](https://www.adafruit.com/product/4383) so you get bright color at any angle. The backlight is also connected to a separate pin so you can PWM the backlight up and down as desired.
For low power usages, the Feather has a *second* low-dropout 3.3V regulator. The regulator is controlled with a GPIO pin on the enable line and can shut off power to the Stemma QT port and TFT. There is also a separate power pin for the NeoPixel that can be used to disable it for even lower quiescent power. With everything off and in deep sleep mode, the TFT feather uses about 100uA of current.
For low power usages, the Feather has a *second* low-dropout 3.3V regulator. The regulator is controlled with a GPIO pin on the enable line and can shut off power to the Stemma QT port and TFT. There is also a separate power pin for the NeoPixel that can be used to disable it for even lower quiescent power. With everything off and in deep sleep mode, the TFT feather uses about 100uA of current.
**Features:**
**Features:**
- **ESP32-S3 Dual Core 240MHz Tensilica processor** - the next generation of ESP32-Sx, with native USB so it can act like a keyboard/mouse, MIDI device, disk drive, etc!
- **Mini module** has FCC/CE certification and comes with 4 MByte of Flash and 2 MByte of PSRAM - you can have huge data buffers
- **[Color 1.14" IPS TFT with 240x135 pixels](https://www.adafruit.com/product/4383)** - bright and colorful display with ST7789 chipset that can be viewed at any angle angle.
- **Power options** - USB type C **or** Lipoly battery
- **Built-in battery charging** when powered over USB-C
- **LiPoly battery monitor** - LC709203 chip actively monitors your battery for voltage and state of charge / percentage reporting over I2C
- **Reset and DFU** (BOOT0) buttons to get into the ROM bootloader (which is a USB serial port so you don't need a separate cable!)
- **Serial debug output pin** (optional, for checking the hardware serial debug console)
- **STEMMA QT** connector for I2C devices, with switchable power, so you can go into low power mode.
- **On/Charge/User** LEDs + status **NeoPixel** with pin-controlled power for low power usage
- **Low Power friendly**! In deep sleep mode, we can get down to 80~100uA of current draw from the Lipoly connection. Quiescent current is from the power regulator, ESP32-S2 chip, and Lipoly monitor. Turn off the NeoPixel and external I2C/TFT power for the lowest quiescent current draw.
- **Works with Arduino or CircuitPython**
- **ESP32-S3 Dual Core 240MHz Tensilica processor** - the next generation of ESP32-Sx, with native USB so it can act like a keyboard/mouse, MIDI device, disk drive, etc!
- **Mini module** has FCC/CE certification and comes with 4 MByte of Flash and 2 MByte of PSRAM - you can have huge data buffers
- **[Color 1.14" IPS TFT with 240x135 pixels](https://www.adafruit.com/product/4383)** - bright and colorful display with ST7789 chipset that can be viewed at any angle angle.
- **Power options** - USB type C **or** Lipoly battery
- **Built-in battery charging** when powered over USB-C
- **LiPoly battery monitor** - LC709203 chip actively monitors your battery for voltage and state of charge / percentage reporting over I2C
- **Reset and DFU** (BOOT0) buttons to get into the ROM bootloader (which is a USB serial port so you don't need a separate cable!)
- **Serial debug output pin** (optional, for checking the hardware serial debug console)
- **STEMMA QT** connector for I2C devices, with switchable power, so you can go into low power mode.
- **On/Charge/User** LEDs + status **NeoPixel** with pin-controlled power for low power usage
- **Low Power friendly**! In deep sleep mode, we can get down to 80~100uA of current draw from the Lipoly connection. Quiescent current is from the power regulator, ESP32-S2 chip, and Lipoly monitor. Turn off the NeoPixel and external I2C/TFT power for the lowest quiescent current draw.
- **Works with Arduino or CircuitPython**
## Purchase

View file

@ -0,0 +1,60 @@
---
layout: download
board_id: "adafruit_huzzah32_breakout"
title: "Adafruit HUZZAH32 Breakout Download"
name: "Adafruit HUZZAH32 Breakout"
manufacturer: "Adafruit"
board_url: "https://www.adafruit.com/product/4172"
board_image: "adafruit_huzzah32_breakout.jpg"
date_added: 2023-3-1
family: esp32
downloads_display: true
features:
- Feather-Compatible
- Battery Charging
- Bluetooth/BTLE
- Wi-Fi
- USB-C
- Breadboard-Friendly
---
Squeeeeze down your next ESP32 project to its bare-bones essential with the **Adafruit HUZZAH32 Breakout**. This breakout is basically the 'big sister' of our HUZZAH 8266, but instead of an ESP8266 it has the '32! We've pared down our popular [Feather ESP32](https://www.adafruit.com/product/3405), removing the battery charger and USB-serial converter. You just get a regulator, some protection diodes, two buttons and an LED. For some projects, where price and size are at a premium, you can program this board over the 'FTDI cable' breakout when needed, and leave it alone otherwise.
Note that this board *doesn't* come with a USB to serial converter chip and auto-reset circuit. Instead, you will need to plug in a [CP2104 Friend](https://www.adafruit.com/product/3309) or [FTDI cable](https://www.adafruit.com/product/70). Then, before uploading code, put it into bootloader mode by holding down the GPIO #0 button and clicking Reset button, then releasing the #0 button.
That module in the middle of the breakout contains a dual-core ESP32 chip, 4 MB of SPI Flash, tuned antenna, and all the passives you need to take advantage of this powerful new processor. The ESP32 has both WiFi *and* Bluetooth Classic/LE support. That means it's perfect for just about any wireless or Internet-connected project.
The ESP32 is a perfect upgrade from the ESP8266 that has been so popular. In comparison, the ESP32 has way more GPIO, plenty of analog inputs, two analog outputs, multiple extra peripherals (like a spare UART), two cores so you don't have to yield to the WiFi manager, much higher-speed processor, etc. etc!
Comes fully assembled and tested, pre-programmed with ESP32 SPI WiFi co-processor firmware that [you can use in CircuitPython to use this into a WiFi co-processsor over SPI + 2 pins](https://github.com/ladyada/Adafruit_CircuitPython_ESP32SPI). We also toss in some header so you can solder it in and plug into a solderless breadboard.
Here are [specifications from Espressif about the ESP32](https://espressif.com/en/products/hardware/esp32/overview):
- 240 MHz dual core Tensilica LX6 microcontroller with 600 DMIPS
- Integrated 520 KB SRAM
- Integrated 802.11b/g/n HT40 Wi-Fi transceiver, baseband, stack and LWIP
- Integrated dual mode Bluetooth (classic and BLE)
- 4 MByte flash include in the WROOM32 module
- On-board PCB antenna
- Ultra-low noise analog amplifier
- Hall sensor
- 10x capacitive touch interface
- 32 kHz crystal oscillator
- 3 x UARTs (only two are configured by default in the Feather Arduino IDE support, one UART is used for bootloading/debug)
- 3 x SPI (only one is configured by default in the Feather Arduino IDE support)
- 2 x I2C (only one is configured by default in the Feather Arduino IDE support)
- 12 x ADC input channels
- 2 x I2S Audio
- 2 x DAC
- PWM/timer input/output available on every GPIO pin
- OpenOCD debug interface with 32 kB TRAX buffer
- SDIO controller/peripheral 50 MHz
- SD-card interface support
**CircuitPython on ESP32**
Want to learn how to load circuitpython onto this board? check out [this](https://learn.adafruit.com/circuitpython-with-esp32-quick-start/) on the Adafruit learning system
Want to use the supernew web workflow, [this](https://learn.adafruit.com/getting-started-with-web-workflow-using-the-code-editor) tutorial shows you how.
## Purchase
* [Adafruit](https://www.adafruit.com/product/4172)

View file

@ -4,11 +4,11 @@ board_id: "adafruit_qtpy_esp32s3_nopsram"
title: "Adafruit QT Py ESP32-S3 No PSRAM Download"
name: "Adafruit QT Py ESP32-S3 No PSRAM"
manufacturer: "Adafruit"
board_url: ""
board_url: "https://www.adafruit.com/product/5426"
board_image: "adafruit_qtpy_esp32s3_nopsram.jpg"
date_added: 2022-2-14
family: esp32s3
bootloader_id: adafruit_qtpy_esp32s3_nopsram
bootloader_id: adafruit_qtpy_esp32s3
downloads_display: true
features:
- STEMMA QT/QWIIC
@ -18,9 +18,40 @@ features:
- Xiao / QTPy Form Factor
---
Coming Soon!
The ESP32-S3 has arrived in QT Py format - and what a great way to get started with this powerful new chip from Espressif! With dual 240 MHz cores, WiFi and BLE support, and native USB, this QT Py is great for powering your IoT projects.
## Learn More
The ESP32-S3 is a highly-integrated, low-power, 2.4 GHz Wi-Fi System-on-Chip (SoC) solution that now has **WiFi** and **BLE** support, **built-in native USB** as well as some other interesting new technologies like Time of Flight distance measurements. With its state-of-the-art power and RF performance, this SoC is an ideal choice for a wide variety of application scenarios relating to the [Internet of Things (IoT)](https://www.adafruit.com/category/342), [wearable electronics](https://www.adafruit.com/category/65), and smart homes.
* [YouTube](https://www.youtube.com/watch?v=Hq5BsjkMBo0)
* [YouTube](https://www.youtube.com/watch?v=py_uFAtV__s)
With native USB and **8 MB Flash** this board will let you upgrade your existing ESP32 projects. Native USB means it can act like a keyboard or a disk drive, and no external USB-to-Serial converter required. WiFi and BLE mean it's awesome for IoT projects.
[OLEDs](https://www.adafruit.com/?q=qt+oled&main_page=category&cPath=1005&sort=BestMatch)! [Inertial Measurement Units](https://www.adafruit.com/?q=qt+imu&main_page=category&cPath=1005&sort=BestMatch)! [Sensors a-plenty](https://www.adafruit.com/?q=qt+sensor&main_page=category&cPath=1005&sort=BestMatch). All plug-and-play thanks to the innovative chainable design: [SparkFun Qwiic](https://www.sparkfun.com/qwiic)-compatible [STEMMA QT](https://learn.adafruit.com/introducing-adafruit-stemma-qt) connectors for the I2C bus so you don't even need to solder! Just plug in a compatible cable and attach it to your MCU of choice, and youre ready to load up some software and measure some light. [Seeed Grove I2C boards](https://www.adafruit.com/product/4528) will also work with this adapter cable.
Pinout and shape are [Seeed Xiao](https://wiki.seeedstudio.com/Seeeduino-XIAO/) compatible, with castellated pads so you can solder it flat to a PCB. In addition to the QT connector, we also added an **RGB NeoPixel** (with controllable power pin to allow for ultra-low-power usage), **a reset button** (great for restarting your program or entering the bootloader), and a button on GPIO 0 for entering the ROM bootloader or for user input
The ESP32-S3 has a dual-core 240 MHz chip, so it is comparable to ESP32's dual-core. However, there is no Bluetooth **Classic** support, only Bluetooth LE. This chip is a great step up from the earlier ESP32-S2! This ESP32-S3 chip we are using on the QT Py comes with 8 MB flash and no PSRAM, but it does have 512KB of SRAM so its fine for use with CircuitPython support as long as massive buffers are not needed. It's also great for use in ESP-IDF or with Arduino support.
- Same size, form-factor, and pin-out as Seeed Xiao
- **USB Type C connector** - [If you have only Micro B cables, this adapter will come in handy](https://www.adafruit.com/product/4299)!
- **ESP32-S3 Dual Core 240MHz Tensilica processor** - the next generation of ESP32-Sx, with native USB so it can act like a keyboard/mouse, MIDI device, disk drive, etc!
- Comes with **8MB Flash, 512KB SRAM, no PSRAM**
- Native USB supported by every OS - can be used in Arduino or CircuitPython as USB serial console, MIDI, Keyboard/Mouse HID, even a little disk drive for storing Python scripts.
- Can be used with **Arduino IDE** or **CircuitPython**
- **Built-in RGB NeoPixel LED** with power control to reduce quiescent power in deep sleep
- Battery input pads on underside with diode protection for external battery packs up to 6V input
- 13 GPIO pins:
- 11 on breakout pads, 2 more on QT connector
- 10 x 12-bit analog inputs (SPI high speed pads do not have analog inputs)
- PWM outputs on any pin
- Two I2C ports, one on the breakout pads, and another with STEMMA QT plug-n-play connector
- Hardware UART
- Hardware SPI on the high speed SPI peripheral pins
- Hardware I2S on any pins
- 5 x Capacitive Touch with no additional components required
- 3.3V regulator with [**600mA peak output**](https://www.diodes.com/assets/Datasheets/AP2112.pdf)
- Light sleep at 2~4mA***,\*** deep sleep at ~70uA
- **Reset switch** for starting your project code over, boot 0 button for entering bootloader mode
- **Really really small**
## Purchase
* [Adafruit](https://www.adafruit.com/product/5426)

24
_board/cosmo_pico.md Normal file
View file

@ -0,0 +1,24 @@
---
layout: download
board_id: "cosmo_pico"
title: "COSMO-Pico Download"
name: "COSMO-Pico"
manufacturer: "Potekku"
board_url: ""
board_image: "cosmo_pico.jpg"
date_added: 2023-3-1
family: raspberrypi
features:
- Wi-Fi
- Bluetooth/BTLE
---
Advanced Design Technology provides technology to major companies based on the development and design of integrated circuits such as LSI and FPGA. "Potekku" also utilizes this know-how to provide a curriculum that specializes in manufacturing.
This time, the pre-launch will start for the March launch of "COSMO Editor", which provides the curriculum on-demand delivery.
"COSMO Editor" is a tool that covers AI / IoT development for children who have never touched a PC and people who want to practice making gadgets.
At the same time, the pre-launch of the board "COSMO Pico", which is suitable for manufacturing and programming learning and has the same CPU as the learning board "Raspberry pi pico", will also start. By using it together with "COSMO Pico", you can make the most of "COSMO Editor", making it easier to learn programming and how things work.
(Translated from [https://edtechzine.jp/article/detail/8715](https://edtechzine.jp/article/detail/8715))

View file

@ -0,0 +1,29 @@
---
layout: download
board_id: "espressif_esp32_lyrat"
title: "ESP32-LyraT Download"
name: "ESP32-LyraT"
manufacturer: "Espressif"
board_url: "https://www.espressif.com/en/products/devkits/esp32-lyrat"
board_image: "espressif_esp32_lyrat.jpg"
date_added: 2023-3-1
family: esp32
features:
- Wi-Fi
- Bluetooth/BTLE
---
ESP32-LyraT is an open-source development board for Espressif Systems Audio Development Framework (ADF). It is designed for smart speakers and smart-home applications. The dev board consists of the ESP32-WROVER-B module, a Micro SD card, expansion interfaces, touch buttons and several function keys.
With a great variety of voice commands, interactive voice functions and a rich peripheral set, ESP32-LyraT allows the fast development of applications relating to consumer electronics, wearables, smart home and industrial automation.
It facilitates the quick and easy development of dual-mode (Bluetooth + Wi-Fi) audio solutions , also supporting one-key Wi-Fi configuration, a wake-up button, voice wake-up, voice recognition, cloud platform access, and an audio player.
- ESP32-WROVER Transceiver
- 802.11 b/g/n (Wi-Fi, WiFi, WLAN)
- Bluetooth® Smart Ready 4.x Dual Mode 2.4GHz Evaluation Board
## Purchase
* [Digi-Key](https://www.digikey.com/en/products/detail/espressif-systems/ESP32-LYRAT/9381704)
* [Mouser](https://www.mouser.com/ProductDetail/Espressif-Systems/ESP32-LyraT?qs=MLItCLRbWsxPzPCja546ZA%3D%3D)

View file

@ -16,8 +16,6 @@ features:
The ESP32-S3-DevKitC-1 is an entry-level development board equipped with ESP32-S3-WROOM-2, a general-purpose Wi-Fi + Bluetooth LE MCU module that integrates complete Wi-Fi and Bluetooth LE functions. **This version is equipped with the ESP32-S3-WROOM-2 (PCB antenna) with 32MB Flash and 8MB PSRAM.**
**Please note:** The S**3** is *similar* to the ESP32-S**2** - but adds a dual-core and Bluetooth LE (not classic!) However, there is minimal support for this dev board. For example, as of the time of this writing, there is no Arduino or CircuitPython support - only ESP IDF! Please purchase if you're doing development with the S3, and OK with stuff not working 100% out of the box.
Most of the I/O pins on the module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S3-DevKitC-1 on a breadboard. We particularly like that there's a debug UART/USB port and a separate native USB port, so you can upload/debug/USB all at once.
At the core of the modules is an ESP32-S3R8V, an Xtensa® 32-bit LX7 CPU that operates at up to 240 MHz. You can power off the CPU and make use of the low-power co-processor to constantly monitor the peripherals for changes or crossing of thresholds. ESP32-S3 integrates a rich set of peripherals including SPI, LCD, Camera interface, UART, I2C, I2S, remote control, pulse counter, LED PWM, USB Serial/JTAG controller, MCPWM, SDIO host, GDMA, TWAI® controller (compatible with ISO 11898-1), ADC, touch sensor, temperature sensor, timers, and watchdogs, as well as up to 45 GPIOs. It also includes a full-speed USB 1.1 On-The-Go (OTG) interface to enable USB communication

View file

@ -16,8 +16,6 @@ features:
The ESP32-S3-DevKitC-1 is an entry-level development board equipped with ESP32-S3-WROOM-1, a general-purpose Wi-Fi + Bluetooth LE MCU module that integrates complete Wi-Fi and Bluetooth LE functions. **This version is equipped with the ESP32-S3-WROOM-1 (PCB antenna) with 8MB Flash and no PSRAM.**
**Please note:** The S**3** is *similar* to the ESP32-S**2** - but adds a dual core and Bluetooth LE (not classic!) However, there is minimal support for this dev board. For example, as of the time of this writing, there is no Arduino or CircuitPython support - only ESP IDF! Please purchase if you're doing development with the S3, and OK with stuff not working 100% out of the box.
Most of the I/O pins on the module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S3-DevKitC-1 on a breadboard. We particularly like that there's a debug UART/USB port and a separate native USB port, so you can upload/debug/USB all at once.
At the core of the module is an ESP32-S3FN8, an Xtensa® 32-bit LX7 CPU that operates at up to 240 MHz. You can power off the CPU and make use of the low-power co-processor to constantly monitor the peripherals for changes or crossing of thresholds.

View file

@ -16,8 +16,6 @@ features:
The ESP32-S3-DevKitC-1 is an entry-level development board equipped with ESP32-S3-WROOM-1, a general-purpose Wi-Fi + Bluetooth LE MCU module that integrates complete Wi-Fi and Bluetooth LE functions. **This version is equipped with the ESP32-S3-WROOM-1 (PCB antenna) with 8MB Flash and 2MB PSRAM.**
**Please note:** The S**3** is *similar* to the ESP32-S**2** - but adds a dual core and Bluetooth LE (not classic!) However, there is minimal support for this dev board. For example, as of the time of this writing, there is no Arduino or CircuitPython support - only ESP IDF! Please purchase if you're doing development with the S3, and OK with stuff not working 100% out of the box.
Most of the I/O pins on the module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S3-DevKitC-1 on a breadboard. We particularly like that there's a debug UART/USB port and a separate native USB port, so you can upload/debug/USB all at once.
At the core of the module is an ESP32-S3FN8, an Xtensa® 32-bit LX7 CPU that operates at up to 240 MHz. You can power off the CPU and make use of the low-power co-processor to constantly monitor the peripherals for changes or crossing of thresholds.

View file

@ -16,8 +16,6 @@ features:
The ESP32-S3-DevKitC-1 is an entry-level development board equipped with ESP32-S3-WROOM-1, a general-purpose Wi-Fi + Bluetooth LE MCU module that integrates complete Wi-Fi and Bluetooth LE functions. **This version is equipped with the ESP32-S3-WROOM-1 (PCB antenna) with 8MB Flash and 8MB PSRAM.**
**Please note:** The S**3** is *similar* to the ESP32-S**2** - but adds a dual core and Bluetooth LE (not classic!) However, there is minimal support for this dev board. For example, as of the time of this writing, there is no Arduino or CircuitPython support - only ESP IDF! Please purchase if you're doing development with the S3, and OK with stuff not working 100% out of the box.
Most of the I/O pins on the module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S3-DevKitC-1 on a breadboard. We particularly like that there's a debug UART/USB port and a separate native USB port, so you can upload/debug/USB all at once.
At the core of the module is an ESP32-S3FN8, an Xtensa® 32-bit LX7 CPU that operates at up to 240 MHz. You can power off the CPU and make use of the low-power co-processor to constantly monitor the peripherals for changes or crossing of thresholds.

View file

@ -16,8 +16,6 @@ features:
The ESP32-S3-DevKitM-1 is an entry-level development board equipped with the ESP32-S3-MINI-1, a powerful, generic Wi-Fi + Bluetooth LE MCU module that features a rich set of peripherals, yet an optimized size. It's an ideal choice for a wide variety of application scenarios related to the Internet of Things (IoT), such as embedded systems, smart homes, wearable electronics, etc. ESP32-S3-MINI-1 comes with a PCB antenna. **This version is equipped with the ESP32-S3-MINI-1 with 8MB Flash.**
**Please note:** The S**3** is *similar* to the ESP32-S**2** - but adds a dual core and Bluetooth LE (not classic!) However, there is minimal support for this dev board. For example, as of the time of this writing, there is no Arduino or CircuitPython support - only ESP IDF! Please purchase if you're doing development with the S3, and OK with stuff not working 100% out of the box.
Most of the I/O pins on the module are broken out to the pin headers on both sides of this board for easy interfacing. Developers can either connect peripherals with jumper wires or mount ESP32-S3-DevKitM-1 on a breadboard.
At the core of the module is an ESP32-S3FN8, an Xtensa® 32-bit LX7 CPU that operates at up to 240 MHz. You can power off the CPU and make use of the low-power co-processor to constantly monitor the peripherals for changes or crossing of thresholds.

View file

@ -0,0 +1,39 @@
---
layout: download
board_id: "espruino_banglejs2"
title: "Espruino Bangle.js v2 Download"
name: "Espruino Bangle.js v2"
manufacturer: "Espruino"
board_url: "https://www.adafruit.com/product/5427"
board_image: "espruino_banglejs2.jpg"
date_added: 2023-3-1
family: nrf52840
features:
- Bluetooth/BTLE
- Battery Charging
- Display
---
**Bangle.js 2 is an open, hackable smartwatch.** With a sunlight-readable always-on screen, 4-week battery life, complete flexibility, and complete control of your data, Bangle.js 2 is a refreshing break from expensive smart watches.
You can install new apps from the web or develop your own using JavaScript. All you need is a Web Browser (Chrome, Edge, or Opera) and you can upload apps or write code to run on your watch wirelessly! Bangle.js is waterproof and comes with Bluetooth Low Energy, GPS, a heart rate monitor, accelerometer, magnetometer, pressure sensor, and more.
**Bangle.js 2.0 specs:**
- IP67 Waterproof (max 1 meter for 30 minutes) **Please note: IP67 does not mean you can wear it while swimming.**
- Nordic 64MHz nRF52840 ARM Cortex-M4 processor with Bluetooth LE
- 256kB RAM, 1MB on-chip flash, 8MB external flash
- 1.3 inch 176x176 always-on 3-bit color LCD display (LPM013M126) with backlight
- Full touchscreen (6H hardness glass)
- GPS/Glonass receiver
- Heart rate monitor
- 3 Axis Accelerometer
- 3 Axis Magnetometer
- Air Pressure/Temperature sensor
- Vibration motor
- 200mAh battery, 4 week standby time
- 36mm x 43mm x 12mm watch body, with standard 20mm watch straps
- Full SWD debug port on back of watch
## Purchase
* [Adafruit](https://www.adafruit.com/product/5427)

18
_board/hack_club_sprig.md Normal file
View file

@ -0,0 +1,18 @@
---
layout: download
board_id: "hack_club_sprig"
title: "Hack Club Sprig Download"
name: "Hack Club Sprig"
manufacturer: "Hack Club"
board_url: "https://sprig.hackclub.com"
board_image: "hack_club_sprig.jpeg"
date_added: "2023-02-03"
family: raspberrypi
features:
- Display
- Speaker
---
The [Sprig](https://sprig.hackclub.com) is a handheld game console made by
[Hack Club](https://hackclub.com). There was one limited production run, which
was distributed for free to teenage makers and coders. It is not for sale.

View file

@ -0,0 +1,31 @@
---
layout: download
board_id: "lilygo_tembed_esp32s3"
title: "T-Embed Download"
name: "T-Embed"
manufacturer: "LILYGO"
board_url: "https://www.lilygo.cc/products/t-embed"
board_image: "lilygo_tembed_esp32s3.jpg"
date_added: 2023-3-1
family: esp32s3
features:
- Wi-Fi
- Bluetooth/BTLE
- Display
- USB-C
- Speaker
---
T-Embed is an IoT embedded panel designed for programmable development. ABS+PC material (optional translucent version) panel + circuit board integrated standardized design, providing product 3D drawings and reference design drawings. Easy design to embed on your product.
## Features & Specifications
* ESP32-S3
* Wi-Fi IEEE 802.11 b/g/n; Bluetooth 5, Bluetooth mesh
* 1.9-inch IPS color TFT LCD
* Rotary encoder + confirmation key in one
* 2.54 x 8pin GPIO interface
## Purchase
* [AliExpress - LILYGO store](https://www.aliexpress.us/item/3256804730566839.html)

View file

@ -44,7 +44,7 @@ A development boards with an OLED and a small form factor.
- `GPIO0` BOOT button
- `GPIO10` LED (blue status LED)
- Lolin I2C JST SH 4-pin port (**does not match QWIIC/Stemma-Qt pinout**) using `GPIO8` (SDA) and `GPIO9` (SCL)
- 128 x 32 SSD1306 OLED display internally connected to the same I2C bus as the external port, reset pin connected to `GPIO18`, I2C address `0x3C` (**not supported in CircuitPython firmware, require user code initialisation**)
- 128 x 32 SSD1306 OLED display internally connected to the same I2C bus as the external port, reset pin connected to `GPIO18`, I2C address `0x3C` (**native support in CircuitPython started with firmware version 8.1.0-beta.0, otherwise user code initialization is required**)
- Compatible with CircuitPython, MicroPython (default firmware), Arduino and ESP-IDF
## Purchase

View file

@ -15,28 +15,27 @@ features:
- Arduino Shield Compatible
---
The NXP iMX RT1011 microcontroller powers the Metro M7 with a 500 MHz ARM Cortex M7 processor. There's 4 MB of execute-in-place QSPI for firmware + disk storage and 128 KB of SRAM in-chip.
Get ready for our fastest Metro ever - the NXP iMX RT1011 microcontroller powers this board with a 500 MHz ARM Cortex M7 processor. There's 4 MB of execute-in-place QSPI for firmware + disk storage and 128KB of SRAM in-chip
## Technical details
We're still working on the design but here's some stuff you can look forward to:
* NXP iMX RT1011 processor - ARM Cortex M7 processor running at 500 MHz, with 128 KB SRAM and high speed USB!
* AirLift WiFi Co-processor, with TLS/SSL support, plenty of RAM for sockets, communication is over SPI
* 4 MB of QSPI XIP Flash
* Power options - 6-12 VDC barrel jack or USB-C
* UNO-shape so shields can plug in
* Reset button - Click to restart, double-click to enter UF2 bootloder
* Boot-mode switches to get into the ROM bootloader (you can always reload code over USB if TinyUF2 gets corrupted somehow)
* SWD connector for advanced debugging access.
* On/Off switch
* STEMMA QT connector for I2C devices
* On/User LEDs + status NeoPixel
* 53.2 mm x 72 mm / 2" x 2.8"
* Height (w/ barrel jack): 14.8 mm / 0.6"
* Weight: 22.5 g
**Features:**
## Learn More
* [YouTube](https://www.youtube.com/watch?v=_sLgycNpMCQ)
- **NXP iMX RT1011 processor** - ARM Cortex M7 processor running at 500 MHz, with 128KB SRAM and high speed USB!
- **AirLift WiFi Co-processor**, with TLS/SSL support, plenty of RAM for sockets, communication is over SPI and has CircuitPython library support ready to go for fast wireless integration.
- **4MB of QSPI XIP Flash**
- **Power options** - 6-12VDC barrel jack **or** USB type C
- **UNO-shape** so shields can plug in
- **Reset** button - Click to restart, double-click to enter UF2 bootloder
- **Boot-mode switches** to get into the ROM bootloader (you can always reload code over USB if TinyUF2 gets corrupted somehow)
- **SWD connector** for advanced debugging access.
- **On/Off switch**
- **STEMMA QT** connector for I2C devices
- **On/User** LEDs + status **NeoPixel**
- **Works with CircuitPython!**
- **53.2mm x 72mm / 2" x 2.8"**
- **Height (w/ barrel jack): 14.8mm / 0.6"**
- **Weight: 22.5g**
## Purchase

View file

@ -2,7 +2,7 @@
layout: download
board_id: "unexpectedmaker_feathers2_prerelease"
title: "Unexpected Maker FeatherS2 Prerelease Download"
name: " Unexpected Maker FeatherS2 Prerelease"
name: "Unexpected Maker FeatherS2 Prerelease"
manufacturer: "Unexpected Maker"
board_url: ""
board_image: "unexpectedmaker_feathers2_prerelease.jpg"
@ -22,7 +22,7 @@ Pre-Release version of the FeatherS2
For those that purchased the pre-release version and would like to run CircuitPython on it without having to compile from source.
**Features & Specifications**
- 32-bit 240 MHz single-core processor
- 32-bit 240 MHz single-core processor
- 16 MB SPI Flash
- 8 MB extra PSRAM
- 2.4 GHz Wi-Fi - 802.11b/g/n
@ -40,7 +40,7 @@ For those that purchased the pre-release version and would like to run CircuitPy
- Feather format
**2x LDO Voltage Regulators?**
Yup! The first one is for the general operation of the board and the ESP32-S2, RAM and Flash.
Yup! The first one is for the general operation of the board and the ESP32-S2, RAM and Flash.
The second LDO is for you to use to connect external 3V3 modules, sensors and peripherals, and it has programmable EN control tied to GPIO21 + its connected to the deep sleep capabilities of the S2, so if the S2 goes into deep sleep, the 2nd LDO is automatically shut down for you!

View file

@ -4,13 +4,13 @@
"version": "0.7.0"
},
"atmel-samd": {
"version": "v3.14.0"
"version": "v3.15.0"
},
"esp32s2": {
"version": "0.12.0"
"version": "0.13.0"
},
"esp32s3": {
"version": "0.12.0"
"version": "0.13.0"
},
"esp32c3": {},
"esp32": {},

File diff suppressed because it is too large Load diff

View file

@ -114,9 +114,9 @@
{% endif %}
{% capture no_extension %}{{ board_url }}/{{ language_code }}/adafruit-circuitpython-{{ board_id }}-{{ language_code }}-{{ version.version }}{% endcapture %}
{% capture files %}{% for ext in version.extensions %}{{ no_extension }}.{{ext}}{% if forloop.last == false %},{% endif %}{% endfor %}{% endcapture %}
<option value={{ files }}
data-files={{ files }}
data-locale={{ language_code | replace: '_', '-' }}
<option value="{{ files }}"
data-files="{{ files }}"
data-locale="{{ language_code | replace: '_', '-' }}"
{% if language_code == "en_US" %}selected{% endif %}>
{{ language_name }}
</option>
@ -128,16 +128,11 @@
<a class="download-button {% if version.stable %}stable{% else %}unstable{% endif %} {{ extension }}" href="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}">DOWNLOAD .{{ extension | upcase }} NOW <i class="fas fa-download" aria-hidden="true"></i></a>
{% endfor %}
{% if page.family == 'esp32s2' or page.family == 'esp32c3' or page.family == 'esp32s3' or page.family == 'esp32' %}
<button is="cp-install-button" class="installer-button" boardname="{{ page.name }}" boardid="{{ board_id }}"
<button is="cp-install-button" class="installer-button" boardid="{{ board_id }}"
{% for extension in version.extensions %}
{{ extension }}file="{{ board_url }}/en_US/adafruit-circuitpython-{{ board_id }}-en_US-{{ version.version }}.{{ extension }}"
{% endfor %}
{% if bootloader_version and bootloader_id %}
bootloader="https://github.com/adafruit/tinyuf2/releases/download/{{ bootloader_version }}/tinyuf2-{{ bootloader_id }}-{{ bootloader_version }}.zip"
bootloaderid="{{ bootloader_id }}"
{% endif %}
version="{{ version.version }}"
chipfamily="{{ page.family }}"
>OPEN INSTALLER <i class="fas fa-magic" aria-hidden="true"></i></button>
{% endif %}
</div>
@ -185,10 +180,8 @@
or if you have older code that depends on features only available in an older release.
Otherwise we recommend using the latest stable release.
</p>
<div>
<div class="previous-versions-buttons">
<a class="download-button-unrecommended" href="https://adafruit-circuit-python.s3.amazonaws.com/index.html?prefix=bin/{{ board_id }}/">BROWSE S3<i class="fas fa-arrow-circle-right" aria-hidden="true"></i></a>
</div>
<div>
<a class="download-button-unrecommended" href="https://github.com/adafruit/circuitpython/releases">BROWSE GITHUB<i class="fab fa-github" aria-hidden="true"></i></a>
</div>
</div>

View file

@ -28,6 +28,6 @@ layout: default
</div>
{% if page.family == 'esp32' or page.family == 'esp32s2' or page.family == 'esp32c3' or page.family == 'esp32s3' %}
<script src="/cpinstaller/src/cpinstaller.js" type="module"></script>
<script src="https://cdn.jsdelivr.net/gh/adafruit/web-firmware-installer-js@latest/dist/cpinstaller.min.js" type="module"></script>
{% endif %}
<script src="/assets/javascript/download.js"></script>

View file

@ -18,7 +18,6 @@
@import 'pages/downloads';
@import 'pages/download';
@import 'pages/awesome';
@import 'pages/stats';
@import 'pages/libraries';
@import 'pages/contributing';
@import 'pages/espinstaller';

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View file

@ -46,6 +46,7 @@ function updateFileLinks(option, language) {
files.forEach(function(file) {
var extension = file.substr(file.lastIndexOf('.') + 1);
parentNode.querySelector(".download-button." + extension).href = file;
parentNode.querySelector(".installer-button").setAttribute(extension + "file", file);
});
}

View file

@ -1,72 +0,0 @@
document.addEventListener('DOMContentLoaded', function() {
async function getBoardStats() {
let response = await fetch('https://api.github.com/repos/adafruit/circuitpython/releases');
let data = await response.json();
return data;
}
function buildBoardStats(data) {
let boards = [];
clearLoadingIndicator();
data.forEach(function(release) {
displayBoardHeader(release);
release.assets.forEach(function(asset) {
let board_name = asset.name.split('-')[2];
let index = boards.findIndex(board => board.name === board_name);
if (index === -1) {
boards.push({name: board_name, downloads: asset.download_count});
} else {
boards[index].downloads += asset.download_count;
}
});
boards.sort(function(a, b) {
return b.downloads - a.downloads;
});
displayBoardStats(boards);
});
}
function clearLoadingIndicator() {
let contentElement = document.querySelector('.stats-wrapper');
contentElement.innerHTML = "";
}
function displayBoardHeader(release) {
let contentElement = document.querySelector('.stats-wrapper');
let h2Element = document.createElement('h2');
let nameContent = document.createTextNode(`${release.tag_name} - ${release.name}`);
h2Element.appendChild(nameContent);
contentElement.appendChild(h2Element);
}
function displayBoardStats(boards) {
let contentElement = document.querySelector('.stats-wrapper');
let table = document.createElement('table');
//header row
let thead = table.createTHead();
let tr = thead.insertRow();
tr.insertCell().appendChild(document.createTextNode("Board"));
tr.insertCell().appendChild(document.createTextNode("Downloads"));
let tbody = table.createTBody();
boards.forEach(function(board) {
let tr = tbody.insertRow();
let name = document.createTextNode(board.name);
let downloads = document.createTextNode(board.downloads);
tr.insertCell().appendChild(name);
tr.insertCell().appendChild(downloads);
});
contentElement.appendChild(table);
}
getBoardStats().then(buildBoardStats);
});

View file

@ -164,6 +164,18 @@
}
}
}
.previous-versions-buttons {
display: flex;
flex-direction: column;
align-items: flex-start;
a, button {
margin-bottom: 1em;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
}

View file

@ -42,6 +42,25 @@
.dialog-body {
margin-top: 24px;
margin-bottom: 20px;
ul.flow-menu {
list-style-type: none;
margin-left: 0;
padding-right: 0;
padding-inline-start: 10px;
li {
a {
padding-left: 10px;
padding-right: 10px;
&:hover {
background: #3498db33;
border-radius: 5px;
}
}
}
}
p.centered {
text-align: center;
@ -51,6 +70,19 @@
width: 100%;
}
div.field {
display: grid;
grid-template-columns: 1fr auto;
grid-gap: 5px;
margin-bottom: 5px;
&:last-of-type {
margin-bottom: 0;
}
input[type="checkbox"] {
margin-right: 8px;
}
}
.loader {
display: block;
position: relative;

View file

@ -1,15 +0,0 @@
#stats-page {
table {
border: 1px solid $gray-border;
border-collapse: collapse;
thead {
font-weight: bold;
}
td {
border: 1px solid $gray-border;
padding: 5px;
}
}
}

View file

@ -1,147 +0,0 @@
<!--
// Wizard screens
// - Menu (installerMenu)
// - Verify user wants to install (installerVerify)
// - erase flash (installerErase)
// - if esp32 or c3 flash bin (installerFlash)
// - if s2 or s3, flash bootloader (installerFlash)
// - if s2 or s3, copy uf2 (May need to use File System Access API)
// - request wifi credentials (skip, connect buttons) and AP password
// - generate and program settings.toml via REPL
// - install complete
-->
<dialog class="installer" id="installerMenu">
</dialog>
<dialog class="installer" id="installerVerify">
</dialog>
<dialog class="installer" id="installerErase">
</dialog>
<!-- Used for flashing either bin or uf2 -->
<dialog class="installer" id="installerFlash">
</dialog>
<dialog class="installer" id="installerCopyUf2">
</dialog>
<dialog class="installer" id="installerCredentials">
</dialog>
<dialog class="installer" id="installerGenerateSettings">
</dialog>
<dialog class="installer" id="installerSuccess">
</dialog>
<dialog class="installer" id="installerError">
</dialog>
<dialog id="installerDialog">
<main class="main">
<div id="notSupported" class="notSupported">
Sorry, <b>Web Serial</b> is not supported on your browser at this time. Browsers we expect to work:
<ul>
<li>Google Chrome 89 (and higher)</li>
<li>Microsoft Edge 89 (and higher)</li>
<li>Opera 75 (and higher)</li>
</ul>
</div>
<div class="subheader">
<div class="left">
<span class="title">ESP32 CircuitPython Installer</span>
<span><strong>This tool will install CircuitPython on ESP32 boards. Click below to see if your board is supported, then follow the instructions to install the firmware.</strong></span>
</div>
</div>
<div id="app">
<ol class="tutorial-steps">
<li class="step-1">
<p>
Make sure your board is plugged into this computer via a Serial connection using a USB Cable.
</p>
<ul>
<li><p><em><strong>NOTE:</strong> A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.</em></p></li>
</ul>
</li>
<li class="step-1">
<p>
<button id="butConnect" type="button">Connect</button>
Click this button to open the Web Serial connection menu.
</p>
<p>There may be many devices listed, such as your remembered Bluetooth peripherals, anything else plugged into USB, etc.</p>
<p>
If you aren't sure which to choose, look for words like "USB", "UART", and "Bridge Controller". There may be more than one right option depending on your system configuration. Experiment if needed.
</p>
</li>
<li class="step-2 hidden">
<p><strong>Do not disconnect your board from your computer from this point!</strong></p>
</li>
<li class="step-2 hidden">
<p>Enter the credentials for the wifi network your board will connect to, as well as the initial Web Workflow password.</p>
<ul>
<li><p><em><strong>NOTE:</strong> Your wifi network must be using 2.4Ghz frequency.</em></p></li>
</ul>
<div id="commands">
<div class="field">
<label><span>WiFi Network Name (SSID):</span>
<input id="network_type_wifi.network_ssid" class="partition-data" type="text" placeholder="WiFi SSID" value="" />
</label>
</div>
<div class="field">
<label><span>WiFi Password:</span>
<input id="network_type_wifi.network_password" class="partition-data" type="text" placeholder="WiFi Password" value="" />
</label>
</div>
<div class="field">
<label><span>Web Workflow Password:</span>
<input id="web_workflow_password" class="partition-data" type="text" placeholder="Web Workflow Password" value="" />
</label>
</div>
</div>
</li>
<li class="step-3 hidden">
<p>Click "Install CircuitPython" to get the process started. If you would like to manually install CircuitPython and simply want to perform a factory reset, click "Install UF2 Bootloader ONLY".</p>
<div class="buttons" style="text-align: center;">
<button id="butProgram" type="button">Install CircuitPython</button>
<button id="butProgramBootloader" type="button">Install UF2 Bootloader ONLY</button>
</div>
</li>
<li class="step-4 hidden">
<p>CircuitPython is installing, please wait...</p>
<div class="buttons">
<div id="stepname" class="hidden"></div>
</div>
<div class="buttons">
<div id="progressBar" class="progress-bar hidden"><div></div></div>
</div>
</li>
<li class="step-5 hidden">
<p>CircuitPython successfully installed. <strong>Reset your board</strong>!</a></p>
</li>
</ol>
</div>
<div id="log" class="hidden console-item"></div>
</main>
</dialog>

View file

@ -1,440 +0,0 @@
'use strict';
import {html, render} from 'https://unpkg.com/lit-html?module';
import * as esptoolPackage from "https://unpkg.com/esp-web-flasher@5.1.2/dist/web/index.js?module"
// TODO: Figure out how to make the Web Serial from ESPTool and Web Serial to communicate with CircuitPython not conflict
// I think at the very least we'll have to reuse the same port so the user doesn't need to reselct, though it's possible it
// may change after reset. Since it's not
//
// For now, we'll use the following procedure for ESP32-S2 and ESP32-S3:
// 1. Install the bin file
// 2. Reset the board
// (if version 8.0.0-beta.6 or later)
// 3. Generate the settings.toml file
// 4. Write the settings.toml to the board via the REPL
// 5. Reset the board again
//
// For the esp32 and esp32c3, the procedure may be slightly different and going through the
// REPL may be required for the settings.toml file.
// 1. Install the bin file
// 2. Reset the board
// (if version 8.0.0-beta.6 or later)
// 3. Generate the settings.toml file
// 4. Write the settings.toml to the board via the REPL
// 5. Reset the board again
//
// To run REPL code, I may need to modularize the work I did for code.circuitpython.org
// That allows you to run code in the REPL and get the output back. I may end up creating a
// library that uses Web Serial and allows you to run code in the REPL and get the output back
// because it's very integrated into the serial recieve and send code.
//
export class InstallButton extends HTMLButtonElement {
static isSupported = 'serial' in navigator;
static isAllowed = window.isSecureContext;
constructor() {
super();
this.dialogElements = {};
this.currentFlow = null;
this.currentStep = 0;
this.currentDialogElement = null;
this.serial = null;
this.espStub = null;
this.mode = "";
this.dialogCssClass = "install-dialog";
this.connected = this.connectionStates.DISCONNECTED;
}
init() {
this.preloadDialogs();
}
// Define some common buttons
/* Buttons should have a label, and a callback and optionally a condition function on whether they should be enabled */
previousButton = {
label: "Previous",
onClick: this.prevStep,
isEnabled: () => { return this.currentStep > 0 },
}
nextButton = {
label: "Next",
onClick: this.nextStep,
isEnabled: () => { return this.currentStep < this.currentFlow.steps.length - 1; },
}
closeButton = {
label: "Close",
onClick: async (e) => {
this.closeDialog();
},
}
// Default Buttons
defaultButtons = [this.previousButton, this.nextButton];
// States and Button Labels
connectionStates = {
DISCONNECTED: "Connect",
CONNECTING: "Connecting...",
CONNECTED: "Disconnect",
}
dialogs = {
notSupported: {
preload: false,
closeable: true,
template: (data) => html`
Sorry, <b>Web Serial</b> is not supported on your browser at this time. Browsers we expect to work:
<ul>
<li>Google Chrome 89 (and higher)</li>
<li>Microsoft Edge 89 (and higher)</li>
<li>Opera 75 (and higher)</li>
</ul>
`,
buttons: [this.closeButton],
},
menu: {
closeable: true,
template: (data) => html`
<p>CircuitPython Installer for ${data.boardName}</p>
<ul class="flow-menu">
${this.generateMenu(
(flowId, flow) => html`<li><a href="#" @click=${this.runFlow.bind(this)} id="${flowId}">${flow.label.replace('[version]', this.releaseVersion)}</a></li>`
)}
</ul>`,
buttons: [this.closeButton],
},
};
flows = {};
baudRates = [
115200,
128000,
153600,
230400,
460800,
921600,
1500000,
2000000,
];
connectedCallback() {
if (InstallButton.isSupported && InstallButton.isAllowed) {
this.toggleAttribute("install-supported", true);
} else {
this.toggleAttribute("install-unsupported", true);
}
this.mode = this.getUrlParam("mode");
this.addEventListener("click", async (e) => {
e.preventDefault();
// WebSerial feature detection
if (!InstallButton.isSupported) {
await this.showNotSupported();
} else {
await this.showMenu();
}
});
}
// Parse out the url parameters from the current url
getUrlParams() {
// This should look for and validate very specific values
var hashParams = {};
if (location.hash) {
location.hash.substr(1).split("&").forEach(function(item) {hashParams[item.split("=")[0]] = item.split("=")[1];});
}
return hashParams;
}
// Get a url parameter by name and optionally remove it from the current url in the process
getUrlParam(name) {
let urlParams = this.getUrlParams();
let paramValue = null;
if (name in urlParams) {
paramValue = urlParams[name];
}
return paramValue;
}
enabledFlowCount() {
let enabledFlowCount = 0;
for (const [flowId, flow] of Object.entries(this.flows)) {
if (flow.isEnabled()) {
enabledFlowCount++;
}
}
return enabledFlowCount;
}
* generateMenu(templateFunc) {
if (this.enabledFlowCount() == 0) {
yield html`<li>Coming soon. Check back later.</li>`;
//yield html`<li>No installable options available for this board.</li>`;
}
for (const [flowId, flow] of Object.entries(this.flows)) {
if (flow.isEnabled()) {
yield templateFunc(flowId, flow);
}
}
}
preloadDialogs() {
for (const [id, dialog] of Object.entries(this.dialogs)) {
if ('preload' in dialog && !dialog.preload) {
continue;
}
this.dialogElements[id] = this.getDialogElement(dialog);
}
}
createIdFromLabel(text) {
return text.replace(/^[^a-z]+|[^\w:.-]+/gi, "");
}
createDialogElement(id, dialogData) {
// Check if an existing dialog with the same id exists and remove it if so
let existingDialog = this.querySelector(`#cp-installer-${id}`);
if (existingDialog) {
this.remove(existingDialog);
}
// Create a dialog element
let dialogElement = document.createElement("dialog");
dialogElement.id = id;
dialogElement.classList.add(this.dialogCssClass);
// Add a close button
let closeButton = document.createElement("button");
closeButton.href = "#";
closeButton.classList.add("close-button");
closeButton.addEventListener("click", (e) => {
e.preventDefault();
dialogElement.close();
});
dialogElement.appendChild(closeButton);
// Add a body element
let body = document.createElement("div");
body.classList.add("dialog-body");
dialogElement.appendChild(body);
let buttons = this.defaultButtons;
if (dialogData && dialogData.buttons) {
buttons = dialogData.buttons;
}
dialogElement.appendChild(
this.createNavigation(buttons)
);
// Return the dialog element
document.body.appendChild(dialogElement);
return dialogElement;
}
createNavigation(buttonData) {
// Add buttons according to config data
const navigation = document.createElement("div");
navigation.classList.add("dialog-navigation");
for (const button of buttonData) {
let buttonElement = document.createElement("button");
buttonElement.innerText = button.label;
buttonElement.id = this.createIdFromLabel(button.label);
buttonElement.addEventListener("click", async (e) => {
e.preventDefault();
await button.onClick.bind(this)();
});
buttonElement.addEventListener("update", async (e) => {
if ("onUpdate" in button) {
await button.onUpdate.bind(this)(e);
}
if ("isEnabled" in button) {
e.target.disabled = !button.isEnabled.bind(this)();
}
});
navigation.appendChild(buttonElement);
}
return navigation;
}
getDialogElement(dialog, forceReload = false) {
function getKeyByValue(object, value) {
return Object.keys(object).find(key => object[key] === value);
}
const dialogId = getKeyByValue(this.dialogs, dialog);
if (dialogId) {
if (dialogId in this.dialogElements && !forceReload) {
return this.dialogElements[dialogId];
} else {
return this.createDialogElement(dialogId, dialog);
}
}
return null;
}
updateButtons() {
// Call each button's custom update event for the current dialog
if (this.currentDialogElement) {
const navButtons = this.currentDialogElement.querySelectorAll(".dialog-navigation button");
for (const button of navButtons) {
button.dispatchEvent(new Event("update"));
}
}
}
showDialog(dialog, templateData = {}) {
if (this.currentDialogElement) {
this.closeDialog();
}
this.currentDialogElement = this.getDialogElement(dialog);
if (!this.currentDialogElement) {
console.error(`Dialog not found`);
}
if (this.currentDialogElement) {
const dialogBody = this.currentDialogElement.querySelector(".dialog-body");
if ('template' in dialog) {
render(dialog.template(templateData), dialogBody);
}
// Close button should probably hide during certain steps such as flashing and erasing
if ("closeable" in dialog && dialog.closeable) {
this.currentDialogElement.querySelector(".close-button").style.display = "block";
} else {
this.currentDialogElement.querySelector(".close-button").style.display = "none";
}
let dialogButtons = this.defaultButtons;
if ('buttons' in dialog) {
dialogButtons = dialog.buttons;
}
this.updateButtons();
this.currentDialogElement.showModal();
}
}
closeDialog() {
this.currentDialogElement.close();
this.currentDialogElement = null;
}
errorMsg(text) {
text = this.stripHtml(text);
console.error(text);
this.showError(text);
}
logMsg(text) {
// TODO: Eventually add to an internal log that the user can bring up
console.info(this.stripHtml(text));
}
updateUIConnected(connected) {
if (Object.values(this.connectionStates).includes(connected)) {
this.connected = connected;
this.updateButtons();
}
}
stripHtml(html) {
let tmp = document.createElement("div");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
formatMacAddr(macAddr) {
return macAddr.map((value) => value.toString(16).toUpperCase().padStart(2, "0")).join(":");
}
async disconnect() {
if (this.espStub) {
await espStub.disconnect();
await espStub.port.close();
this.updateUIConnected(this.connectionStates.DISCONNECTED);
this.espStub = null;
}
}
async runFlow(flow) {
if (flow instanceof Event) {
flow.preventDefault();
flow.stopImmediatePropagation();
if (flow.target.id in this.flows) {
flow = this.flows[flow.target.id];
} else {
return;
}
}
this.currentFlow = flow;
this.currentStep = 0;
await this.currentFlow.steps[this.currentStep].bind(this)();
}
async nextStep() {
if (!this.currentFlow) {
return;
}
if (this.currentStep < this.currentFlow.steps.length) {
this.currentStep++;
await this.currentFlow.steps[this.currentStep].bind(this)();
}
}
async prevStep() {
if (!this.currentFlow) {
return;
}
if (this.currentStep > 0) {
this.currentStep--;
await this.currentFlow.steps[this.currentStep].bind(this)();
}
}
async showMenu() {
// Display Menu
this.showDialog(this.dialogs.menu, {boardName: this.boardName});
}
async showNotSupported() {
// Display Not Supported Message
this.showDialog(this.dialogs.notSupported);
}
async showError(message) {
// Display Menu
this.showDialog(this.dialogs.error, {message: message});
}
async setBaudRateIfChipSupports(chipType, baud) {
if (baud == esptoolPackage.ESP_ROM_BAUD) { return } // already the default
if (chipType == esptoolPackage.CHIP_FAMILY_ESP32) { // only supports the default
this.logMsg("WARNING: ESP32 is having issues working at speeds faster than 115200. Continuing at 115200 for now...");
return
}
await this.changeBaudRate(baud);
}
async changeBaudRate(baud) {
if (this.espStub && this.baudRates.includes(baud)) {
await this.espStub.setBaudrate(baud);
}
}
}

View file

@ -1,856 +0,0 @@
'use strict';
import { html } from 'https://unpkg.com/lit-html?module';
import * as zip from "https://deno.land/x/zipjs/index.js";
import * as esptoolPackage from "https://unpkg.com/esp-web-flasher@5.1.2/dist/web/index.js?module"
import {REPL} from 'https://cdn.jsdelivr.net/gh/adafruit/circuitpython-repl-js@1.0.0/repl.js';
import { InstallButton } from "./base_installer.js";
// TODO: Figure out how to make the Web Serial from ESPTool and Web Serial to communicate with CircuitPython not conflict
// I think at the very least we'll have to reuse the same port so the user doesn't need to reselct, though it's possible it
// may change after reset. Since it's not
//
// For now, we'll use the following procedure for ESP32-S2 and ESP32-S3:
// 1. Install the bin file
// 2. Reset the board
// (if version 8.0.0-beta.6 or later)
// 3. Generate the settings.toml file
// 4. Write the settings.toml to the board via the REPL
// 5. Reset the board again
//
// For the esp32 and esp32c3, the procedure may be slightly different and going through the
// REPL may be required for the settings.toml file.
// 1. Install the bin file
// 2. Reset the board
// (if version 8.0.0-beta.6 or later)
// 3. Generate the settings.toml file
// 4. Write the settings.toml to the board via the REPL
// 5. Reset the board again
//
const PREFERRED_BAUDRATE = 921600;
const CSS_DIALOG_CLASS = "cp-installer-dialog";
const FAMILY_TO_CHIP_MAP = {
'esp32s2': esptoolPackage.CHIP_FAMILY_ESP32S2,
'esp32s3': esptoolPackage.CHIP_FAMILY_ESP32S3,
'esp32c3': esptoolPackage.CHIP_FAMILY_ESP32C3,
'esp32': esptoolPackage.CHIP_FAMILY_ESP32
}
export class CPInstallButton extends InstallButton {
constructor() {
super();
this.releaseVersion = "[version]";
this.boardName = "ESP32-based device";
this.boardId = null;
this.bootloaderUrl = "";
this.uf2FileUrl = "";
this.binFileUrl = "";
this.releaseVersion = 0;
this.chipFamily = null;
this.bootloadId = null;
this.dialogCssClass = CSS_DIALOG_CLASS;
this.dialogs = { ...this.dialogs, ...this.cpDialogs };
this.init();
}
connectedCallback() {
this.boardName = this.getAttribute("boardname") || "ESP32-based device";
// If this is empty, it's a problem
this.boardId = this.getAttribute("boardid");
this.releaseVersion = this.getAttribute("version");
// We need either the bootloader and uf2 or bin file to continue
this.bootloaderUrl = this.getAttribute("bootloader");
this.uf2FileUrl = this.getAttribute("uf2file");
this.binFileUrl = this.getAttribute("binfile");
// Nice to have for now
this.chipFamily = this.getAttribute("chipfamily");
this.bootloadId = this.getAttribute("bootloadid"); // This could be used to check serial output from board matches the UF2 file
super.connectedCallback();
}
// This may end up moving to a superclass that extends the installer
// These are a series of the valid steps that should be part of a program flow
flows = {
binProgram: {
label: `Install CircuitPython [version] Bin`,
steps: [this.stepSerialConnect, this.stepConfirm, this.stepEraseAll, this.stepFlashBin, this.stepSuccess],
isEnabled: () => { return this.mode=="test" && !!this.binFileUrl },
},
uf2Program: {
label: `Install CircuitPython [version] UF2 and Bootloader`,
steps: [this.stepSerialConnect, this.stepConfirm, this.stepEraseAll, this.stepBootloader, this.stepCopyUf2, this.stepSettings, this.stepSuccess],
isEnabled: () => { return this.mode=="test" && !!this.bootloaderUrl && !!this.uf2FileUrl },
},
bootloaderOnly: {
label: "Install Bootloader Only",
steps: [this.stepSerialConnect, this.stepConfirm, this.stepEraseAll, this.stepBootloader, this.stepSuccess],
isEnabled: () => { return this.mode=="test" && !!this.bootloaderUrl },
},
settingsOnly: {
label: "Update WiFi credentials",
steps: [this.stepSerialConnect, this.stepCredentials, this.stepSettings, this.stepSuccess],
isEnabled: () => { return this.mode=="test" && this.cpDetected() },
}
}
// This is the data for the dialogs
cpDialogs = {
serialConnect: {
closeable: true,
template: (data) => html`
<p>
Welcome to the CircuitPython Installer. This tool will install CircuitPython on your ${data.boardName}.
</p>
<p>Make sure your board is plugged into this computer via a Serial connection using a USB Cable.
</p>
<ul>
<li><em><strong>NOTE:</strong> A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.</em></li>
</ul>
<p>
<button id="butConnect" type="button" @click=${this.connectHandler.bind(this)}>Connect</button>
Click this button to open the Web Serial connection menu.
</p>
<p>There may be many devices listed, such as your remembered Bluetooth peripherals, anything else plugged into USB, etc.</p>
<p>
If you aren't sure which to choose, look for words like "USB", "UART", and "Bridge Controller". There may be more than one right option depending on your system configuration. Experiment if needed.
</p>
`,
buttons: [this.previousButton, {
label: "Next",
onClick: this.nextStep,
isEnabled: () => { return (this.currentStep < this.currentFlow.steps.length - 1) && this.connected == this.connectionStates.CONNECTED },
onUpdate: async (e) => { console.log("updating"); this.currentDialogElement.querySelector("#butConnect").innerText = this.connected; },
}],
},
confirm: {
template: (data) => html`
<p>This will overwrite everything on the ${data.boardName}.</p>
`,
buttons: [
this.previousButton,
{
label: "Continue",
onClick: this.nextStep,
}
],
},
erase: {
template: (data) => html`
<p class="centered">Erasing Flash...</p>
<div class="loader"><div></div><div></div><div></div><div></div></div>
`,
buttons: [],
},
flash: {
template: (data) => html`
<p class="centered">${data.action} ${data.file}...</p>
<progress id="flashProgress" max="100" value="0"></progress>
`,
buttons: [],
},
// We may have a waiting for Bootloader to start dialog
copyUf2: {
template: (data) => html`
<p class="centered">Copying ${data.file}...</p>
<progress id="copyProgress" max="100" value="0"></progress>
`,
buttons: [this.nextButton],
},
credentials: {
template: (data) => html`
<div class="field">
<label for="circuitpy_wifi_ssid">WiFi Network Name (SSID):</label>
<input id="circuitpy_wifi_ssid" class="setting-data" type="text" placeholder="WiFi SSID" value="" />
</div>
<div class="field">
<label for="circuitpy_wifi_password">WiFi Password:</label>
<input id="circuitpy_wifi_password" class="setting-data" type="text" placeholder="WiFi Password" value="" />
</div>
<div class="field">
<label for="circuitpy_web_api_password">Web Workflow API Password:</label>
<input id="circuitpy_web_api_password" class="setting-data" type="text" placeholder="Web Workflow API Password" value="" />
</div>
<div class="field">
<!-- Alternatively "Disable USB Mass Storage" -->
<input id="circuitpy_drive" class="setting" type="checkbox" value="disabled" checked />
<label for="circuitpy_drive">Disable CIRCUITPY Drive (Required for write access)</label>
</div>
`,
},
circuitPythonCheck: {
template: (data) => html`
<p>Looking for CircuitPython...</p>
<progress id="copyProgress" max="100" value="${data.percentage}"> ${data.percentage}% </progress>
`,
},
setUpWebWorkflow: {
template: (data) => html`
<p>Setting up Web Workflow...</p>
<progress id="copyProgress" max="100" value="${data.percentage}"> ${data.percentage}% </progress>
`,
},
success: {
closeable: true,
template: (data) => html`
<p>Successfully Completed Installation</p>
`,
buttons: [this.closeButton],
},
error: {
closeable: true,
template: (data) => html`
<p>Installation Error: ${data.message}</p>
`,
closeable: false,
buttons: [this.closeButton],
},
}
async connectHandler(e) {
await this.disconnect();
let esploader;
try {
esploader = await esptoolPackage.connect({
log: (...args) => this.logMsg(...args),
debug: (...args) => {},
error: (...args) => this.errorMsg(...args),
});
} catch (err) {
this.errorMsg("Unable to open Serial connection to board. Make sure the port is not already in use by another application or in another browser tab.");
return;
}
try {
this.updateUIConnected(this.connectionStates.CONNECTING);
await esploader.initialize();
this.updateUIConnected(this.connectionStates.CONNECTED);
} catch (err) {
await esploader.disconnect();
// Disconnection before complete
this.updateUIConnected(this.connectionStates.DISCONNECTED);
this.errorMsg("Unable to connect to the board. Make sure it is in bootloader mode by holding the boot0 button when powering on and try again.")
return;
}
try {
this.logMsg("Connected to " + esploader.chipName);
this.logMsg("MAC Address: " + this.formatMacAddr(esploader.macAddr()));
// check chip compatibility
if (FAMILY_TO_CHIP_MAP[this.chipFamily] == esploader.chipFamily) {
console.log("This chip checks out");
this.espStub = await esploader.runStub();
this.espStub.addEventListener("disconnect", () => {
this.updateUIConnected(this.connectionStates.DISCONNECTED);
this.espStub = null;
});
await this.setBaudRateIfChipSupports(esploader.chipFamily, PREFERRED_BAUDRATE);
return
}
// Can't use it so disconnect now
this.errorMsg("Oops, this is the wrong firmware for your board.")
await this.disconnect()
} catch (err) {
await esploader.disconnect();
// Disconnection before complete
this.updateUIConnected(this.connectionStates.DISCONNECTED);
this.errorMsg("Oops, we lost connection to your board before completing the install. Please check your USB connection and click Connect again. Refresh the browser if it becomes unresponsive.")
}
}
async stepSerialConnect() {
// Display Serial Connect Dialog
this.showDialog(this.dialogs.serialConnect, {boardName: this.boardName});
}
async stepConfirm() {
// Display Confirm Dialog
this.showDialog(this.dialogs.confirm, {boardName: this.boardName});
}
async stepEraseAll() {
// Display Erase Dialog
this.showDialog(this.dialogs.erase);
try {
await this.espStub.eraseFlash();
} catch (err) {
this.errorMsg("Unable to finish erasing Flash memory. Please try again.");
}
await this.nextStep();
}
async stepFlashBin() {
if (!this.binFileUrl) {
// We shouldn't be able to get here, but just in case
this.errorMsg("Missing bin file URL. Please make sure the installer button has this specified.");
return;
}
await this.downloadAndInstall(this.binFileUrl);
await this.nextStep();
}
async stepBootloader() {
if (!this.bootloaderUrl) {
// We shouldn't be able to get here, but just in case
this.errorMsg("Missing bootloader file URL. Please make sure the installer button has this specified.");
return;
}
// Display Bootloader Dialog
await this.downloadAndInstall(this.bootloaderUrl, 'combined.bin');
// TODO: Reboot into bootloader
await this.nextStep();
}
async stepCopyUf2() {
// Display CopyUf2 Dialog
this.showDialog(this.dialogs.copyUf2, {file: this.uf2FileUrl});
}
async stepSettings() {
// Display Settings Dialog
this.showDialog(this.dialogs.settings);
}
async stepCredentials() {
// Display Credentials Request Dialog
this.showDialog(this.dialogs.credentials);
}
async stepWebWorkflow() {
// Display Dialog to set up Web Workflow
// Wait for CircuitPython to be detected
// Write the Settings.toml file
// If Disable CIRCUITPY Drive was checked, write the boot.py file
// Reboot
this.showDialog(this.dialogs.setUpWebWorkflow);
}
async stepSuccess() {
// Display Success Dialog
this.showDialog(this.dialogs.success);
// If we were setting up Web Workflow, we may want to provide a link to code.circuitpython.org
// Alternatively, we may want a separate dialog with a link
}
async stepClose() {
// Close the currently loaded dialog
this.closeDialog();
}
cpDetected() {
// TODO: Actually detect CircuitPython
// We may also want to have it return the version number and return null if not detected
return false;
}
async downloadFile(url, progressElement) {
let response;
try {
response = await fetch(url, {mode: "cors"});
} catch (err) {
this.errorMsg("Unable to download file: " + url);
return null;
}
const body = response.body;
const reader = body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
let chunks = [];
while(true) {
const {done, value} = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
progressElement.value = Math.round(receivedLength / contentLength) * 100;
console.log(`Received ${receivedLength} of ${contentLength}`)
}
let chunksAll = new Uint8Array(receivedLength);
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position);
position += chunk.length;
}
let result = new Blob([chunksAll]);
return result;
}
async downloadAndInstall(url, fileToExtract = null) {
// Display Flash Dialog
let filename = url.split("/").pop();
this.showDialog(this.dialogs.flash, {
action: "Downloading",
file: filename,
});
const progressElement = this.currentDialogElement.querySelector("#flashProgress");
// Download the file at the url updating the progress in the process
let fileContents = await this.downloadFile(url, progressElement);
// If the file is a zip file, unzip and find the file to extract
if (filename.endsWith(".zip") && fileToExtract) {
let foundFile;
console.log("Extracting step");
// Update the flash dialog
this.showDialog(this.dialogs.flash, {
action: "Extracting",
file: fileToExtract,
});
// Set that to the current file to flash
[foundFile, fileContents] = await this.findAndExtractFromZip(fileContents, fileToExtract);
if (!fileContents) {
this.errorMsg("Unable to find " + fileToExtract + " in " + filename);
return;
}
filename = foundFile;
}
// Update the flash dialog
if (fileContents) {
console.log("Flash step");
let lastPercent = 0;
this.showDialog(this.dialogs.flash, {
action: "Flashing",
file: filename,
});
try {
await this.espStub.flashData(fileContents, (bytesWritten, totalBytes) => {
let percentage = Math.floor((bytesWritten / totalBytes) * 100);
if (percentage != lastPercent) {
progressElement.value = percentage;
this.logMsg(`${percentage}% (${bytesWritten}/${totalBytes})...`);
lastPercent = percentage;
}
}, 0, 0);
} catch (err) {
this.errorMsg("Unable to flash file: " + filename);
console.log(err);
}
}
}
async findAndExtractFromZip(zipBlob, filename) {
const reader = new zip.ZipReader(new zip.BlobReader(zipBlob));
// unzip into local file cache
let zipContents = await reader.getEntries();
for(const zipEntry of zipContents) {
console.log(filename, zipEntry.filename, zipEntry.filename.localeCompare(filename));
if (zipEntry.filename.localeCompare(filename) === 0) {
const extractedFile = await zipEntry.getData(new zip.Uint8ArrayWriter());
return [zipEntry.filename, extractedFile.buffer]; // ESPTool wants an ArrayBuffer
}
}
return [null, null];
}
}
customElements.define('cp-install-button', CPInstallButton, {extends: "button"});
// Changes to make:
// Hide the log and make it accessible via the menu (future feature, console.log for now)
// Generate dialogs on the fly
// Make a drop-in component
// Keep in mind it will be used for LEARN too
// May need to deal with CORS issues
// May need to deal with the fact that the ESPTool uses Web Serial and CircuitPython REPL uses Web Serial
/*
const maxLogLength = 100;
const disableWhileBusy = [partitionData, butProgram, butProgramBootloader, baudRate];
document.addEventListener("DOMContentLoaded", () => {
// register dom event listeners
butConnect.addEventListener("click", () => {
clickConnect().catch(async (e) => {
// Default Help Message:
// if we've failed to catch the message before now, we need to give
// the generic advice: reconnect, refresh, go to support
this.errorMsg(
`Connection Error, your board may be incompatible. Things to try:\n` +
`1. Reset your board and try again.\n` +
` - Look for a little black button near the power port.\n` +
`2. Refresh your browser and try again.\n` +
`3. Make sure you are not connected in another browser tab.\n` +
`4. Double-check your board type and serial port selection.\n` +
`5. Post on the Support Forum (link above) with this info:\n\n` +
`"Firmware Tool: ${e}"\n`
);
await disconnect();
updateUIConnected(this.connectionStates.DISCONNECTED);
});
});
//butClear.addEventListener("click", clickClear);
butProgram.addEventListener("click", clickProgram);
butProgramBootloader.addEventListener("click", clickProgramNvm);
for (let i = 0; i < partitionData.length; i++) {
partitionData[i].addEventListener("change", checkProgrammable);
partitionData[i].addEventListener("keydown", checkProgrammable);
partitionData[i].addEventListener("input", checkProgrammable);
}
//autoscroll.addEventListener("click", clickAutoscroll);
//baudRate.addEventListener("change", changeBaudRate);
// handle runaway errors
window.addEventListener("error", event => {
console.warn(`Uncaught error: ${event.error}`);
});
// handle runaway rejections
window.addEventListener("unhandledrejection", event => {
console.warn(`Unhandled rejection: ${event.reason}`);
});
// WebSerial feature detection
if ("serial" in navigator) {
const notSupported = document.getElementById("notSupported");
notSupported.classList.add("hidden");
}
//initBinSelector();
//initBaudRate();
loadAllSettings();
this.logMsg("CircuitPython ESP32 Installer loaded.");
checkProgrammable();
});
let latestFirmwares = []
function doThingOnClass(method, thing, classSelector) {
const classItems = document.getElementsByClassName(classSelector)
for (let idx = 0; idx < classItems.length; idx++) {
classItems.item(idx).classList[method](thing)
}
}
function setDefaultBoard() {
const board = getFromQuerystring(QUERYSTRING_BOARD_KEY)
if (board && hasBoard(board)) {
binSelector.value = board
return true
}
}
function hasBoard(board) {
for (let opt of binSelector.options) {
if (opt.value == board) { return opt }
}
}
function toggleConsole(show) {
// hide/show the console log and its widgets
const consoleItemsMethod = show ? "remove" : "add"
for (let idx = 0; idx < consoleItems.length; idx++) {
consoleItems.item(idx).classList[consoleItemsMethod]("hidden")
}
// toggle the button
//butShowConsole.checked = show
// tell the app if it's sharing space with the console
const appDivMethod = show ? "add" : "remove"
appDiv.classList[appDivMethod]("with-console")
// scroll both to the bottom a moment after adding
setTimeout(() => {
log.scrollTop = log.scrollHeight
appDiv.scrollTop = appDiv.scrollHeight
}, 200)
}
let semver
function initSemver(newSemver) {
if (!newSemver) { return }
semver = newSemver
semverLabel.innerHTML = semver
return true
}
function lookupFirmwareByBinSelector() {
// get the currently selected board id
const selectedId = binSelector.value
if (!selectedId || selectedId === 'null') { throw new Error("No board selected.") }
// grab the stored firmware settings for this id
let selectedFirmware
for (let firmware of latestFirmwares) {
if (firmware.id === selectedId) {
selectedFirmware = firmware
break
}
}
if (!selectedFirmware) {
const { text, value } = binSelector.selectedOptions[0]
throw new Error(`No firmware entry for: ${text} (${value})`)
}
return selectedFirmware
}
let lastPercent = 0;
async function clickAutoscroll() {
saveSetting("autoscroll", autoscroll.checked);
}
async function clickProgram() {
await programScript(full_bin_program);
}
async function clickProgramNvm() {
await programScript(factory_reset_program);
}
async function populateSecretsFile(path) {
let response = await fetch(path);
let contents = await response.json();
// Get the secrets data
for (let field of getValidFields()) {
const { id, value } = partitionData[field]
if(id === "status_pixel_brightness") {
const floatValue = parseFloat(value)
updateObject(contents, id, isNaN(floatValue) ? 0.2 : floatValue);
} else {
updateObject(contents, id, value);
}
}
// Convert the data to text and return
return JSON.stringify(contents, null, 4);
}
function updateObject(obj, path, value) {
if (typeof obj === "undefined") {
return false;
}
var _index = path.indexOf(".");
if (_index > -1) {
return updateObject(obj[path.substring(0, _index)], path.substr(_index + 1), value);
}
obj[path] = value;
}
async function mergeSettings() {
const { settings } = lookupFirmwareByBinSelector()
const transformedSettings = {
...settings,
// convert the offset value from hex string to number
offset: parseInt(settings.offset, 16),
// replace the structure object with one where the keys have been converted
// from hex strings to numbers
structure: Object.keys(settings.structure).reduce((newObj, hexString) => {
// new object, converted key (hex string -> numeric), same value
newObj[parseInt(hexString, 16)] = settings.structure[hexString]
return newObj
}, {})
}
// merge with the defaults and send back
return {
...BASE_SETTINGS,
...transformedSettings
}
}
async function programScript(stages) {
butProgram.disabled = true
butProgramNvm.disabled = true
try {
await fetchFirmwareForSelectedBoard()
} catch(error) {
this.errorMsg(error.message)
return
}
// pretty print the settings object with VERSION placeholders filled
const settings = await mergeSettings()
const settingsString = JSON.stringify(settings, null, 2)
const strippedSettings = settingsString.replaceAll('VERSION', semver)
this.logMsg(`Flashing with settings: <pre>${strippedSettings}</pre>`)
let steps = [];
for (let i = 0; i < stages.length; i++) {
if (stages[i] == stage_erase_all) {
steps.push({
name: "Erasing Flash",
func: async function () {
await this.espStub.eraseFlash();
},
params: {},
});
} else if (stages[i] == stage_flash_cpbin) {
for (const [offset, filename] of Object.entries(settings.structure)) {
steps.push({
name: "Flashing " + filename.replace('VERSION', semver),
func: async function (params) {
const firmware = await getFirmware(params.filename);
const progressBar = progress.querySelector("div");
lastPercent = 0;
await this.espStub.flashData(
firmware,
(bytesWritten, totalBytes
) => {
let percentage = Math.floor((bytesWritten / totalBytes) * 100)
if (percentage != lastPercent) {
this.logMsg(`${percentage}% (${bytesWritten}/${totalBytes})...`);
lastPercent = percentage;
}
progressBar.style.width = percentage + "%";
},
params.offset,
0
);
},
params: {
filename: filename,
offset: offset,
},
});
}
} else if (stages[i] == stage_flash_bootloader) {
for (const [offset, filename] of Object.entries(settings.structure)) {
steps.push({
name: "Flashing " + filename.replace('VERSION', semver),
func: async function (params) {
const firmware = await getFirmware(params.filename);
const progressBar = progress.querySelector("div");
lastPercent = 0;
await this.espStub.flashData(
firmware,
(bytesWritten, totalBytes
) => {
let percentage = Math.floor((bytesWritten / totalBytes) * 100)
if (percentage != lastPercent) {
this.logMsg(`${percentage}% (${bytesWritten}/${totalBytes})...`);
lastPercent = percentage;
}
progressBar.style.width = percentage + "%";
},
params.offset,
0
);
},
params: {
filename: filename,
offset: offset,
},
});
}
} else if (stages[i] == stage_program_settings) {
// TODO: This needs to be rewritten to talk with circuitpython
// and run python code via the repl to write a settings.toml file
// See https://learn.adafruit.com/circuitpython-with-esp32-quick-start/setting-up-web-workflow
// and https://github.com/circuitpython/web-editor/pull/46
steps.push({
name: "Generating and Writing the WiFi Settings",
func: async function (params) {
let fileSystemImage = await generate(params.flashParams);
if (DO_DOWNLOAD) {
// Download the Partition
var blob = new Blob([new Uint8Array(fileSystemImage)], {
type: "application/octet-stream",
});
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "littleFS.bin";
link.click();
link.remove();
} else {
const progressBar = progress.querySelector("div");
lastPercent = 0;
await this.espStub.flashData(
new Uint8Array(fileSystemImage).buffer,
(bytesWritten, totalBytes) => {
let percentage = Math.floor((bytesWritten / totalBytes) * 100)
if (percentage != lastPercent) {
this.logMsg(`${percentage}% (${bytesWritten}/${totalBytes})...`);
lastPercent = percentage;
}
progressBar.style.width = percentage + "%";
},
params.flashParams.offset,
0
);
}
},
params: {
flashParams: settings,
},
});
}
}
for (let i = 0; i < disableWhileBusy.length; i++) {
if (Array.isArray(disableWhileBusy[i])) {
for (let j = 0; j < disableWhileBusy[i].length; i++) {
disableWhileBusy[i][j].disable = true;
}
} else {
disableWhileBusy[i].disable = true;
}
}
progress.classList.remove("hidden");
stepname.classList.remove("hidden");
showStep(5)
for (let i = 0; i < steps.length; i++) {
stepname.innerText = steps[i].name + " (" + (i + 1) + "/" + steps.length + ")...";
await steps[i].func(steps[i].params);
}
stepname.classList.add("hidden");
stepname.innerText = "";
progress.classList.add("hidden");
progress.querySelector("div").style.width = "0";
for (let i = 0; i < disableWhileBusy.length; i++) {
if (Array.isArray(disableWhileBusy[i])) {
for (let j = 0; j < disableWhileBusy[i].length; i++) {
disableWhileBusy[i][j].disable = false;
}
} else {
disableWhileBusy[i].disable = false;
}
}
checkProgrammable();
await disconnect();
this.logMsg("To run the new firmware, please reset your device.");
showStep(6);
}
*/

View file

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.cls-1{fill:#fff;opacity:0;}.cls-2{fill:#231f20;}</style></defs><title>close</title><g id="Layer_2" data-name="Layer 2"><g id="close"><g id="close-2" data-name="close"><rect class="cls-1" width="24" height="24" transform="translate(24 24) rotate(180)"/><path class="cls-2" d="M13.41,12l4.3-4.29a1,1,0,1,0-1.42-1.42L12,10.59,7.71,6.29A1,1,0,0,0,6.29,7.71L10.59,12l-4.3,4.29a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L12,13.41l4.29,4.3a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42Z"/></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 553 B

89
generate-board-info.py Normal file
View file

@ -0,0 +1,89 @@
#!/usr/bin/python3
import json
from pathlib import Path
import frontmatter
import argparse
INCLUDED_CHIP_FAMILIES = ("esp32s2", "esp32s3", "esp32c3", "esp32")
BOOTLOADER_URL_PREFIX = (
"https://adafruit-circuit-python.s3.amazonaws.com/bootloaders/esp32/"
)
DOWNLOAD_URL_PREFIX = "https://adafruit-circuit-python.s3.amazonaws.com/bin/"
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"-o",
"--output",
help="Output filename. If not specified, output will just print to screen.",
type=str,
)
args = parser.parse_args()
# Get CircuitPython Bootloader Info
with open("./_data/bootloaders.json", "rt") as f:
bootloaders = json.load(f)['bootloaders']
with open("./_data/files.json", "rt") as f:
board_info = json.load(f)
def get_releases(board_id):
releases = []
for board in board_info:
if board_id in board["id"]:
for board_releases in board["versions"]:
release = {}
release["version"] = board_releases["version"]
for extension in board_releases["extensions"]:
release[
f"{extension}file"
] = f'{DOWNLOAD_URL_PREFIX}{board_id}/en_US/adafruit-circuitpython-{board_id}-en_US-{release["version"]}.{extension}'
releases.append(release)
break
return releases
def get_bootloader(chipfamily, bootloader_id):
if chipfamily in bootloaders and "version" in bootloaders[chipfamily]:
bootloader_version = bootloaders[chipfamily]["version"]
return f"{BOOTLOADER_URL_PREFIX}tinyuf2-{bootloader_id}-{bootloader_version}.zip"
return None
def generate_boards(folder):
boards = {}
for filename in Path(folder).glob("*.md"):
board = {}
with open(filename, "rt") as f:
metadata, _ = frontmatter.parse(f.read())
downloads_display = metadata.get("downloads_display")
if downloads_display is None or downloads_display:
board_id = metadata.get("board_id").strip() or ()
if board_id == "unknown":
continue
board["name"] = metadata.get("name").strip()
board["chipfamily"] = metadata.get("family").strip()
if board["chipfamily"] not in INCLUDED_CHIP_FAMILIES:
continue
bootloader_id = metadata.get("bootloader_id")
if board["chipfamily"] and bootloader_id:
board["bootloader"] = get_bootloader(
board["chipfamily"], bootloader_id
)
board["releases"] = get_releases(board_id)
boards[board_id] = board
print(f"Added {board_id}")
return boards
boards = generate_boards("_board")
if args.output:
with open(args.output, "wt") as f:
json.dump(boards, f, indent=4)
print(f"Wrote {args.output}")
else:
print(json.dumps(boards, indent=4))
if __name__ == "__main__":
main()

View file

@ -1,16 +0,0 @@
---
layout: home
title: Stats
permalink: /stats
---
<div id="stats-page" class="common-layout">
<div class="content">
<h1>CircuitPython Download Stats</h1>
<div class="stats-wrapper">
Loading Stats...
</div>
</div>
</div>
<script src="/assets/javascript/stats.js"></script>