Close
0%
0%

SeaGL 2025 Badge (Unofficial)

An interactive badge for the Seattle GNU/Linux Conference with live hashtag updates for the event.

Public Chat
Similar projects worth following
65 views
0 followers
So this is a project to make a simple badge to use at the SeaGL 2025 Conference. It will scroll through several screens providing basic contact information and then the three most recent posts on Bluesky with the #SeaGL2025 hashtag. It uses a Lilygo T-Display ESP32, 3000mAh battery, and 3d printed case.

So it is my first time attending the Seattle GNU/Linux Conference, and in fact any tech oriented conference, and I wanted to have an ice breaker. So I am making a name badge with a Lilygo T-Display with the ESP32 and connecting it to my phone via wifi for Internet. 

It will scroll through several screens:

  1. Introduction
  2. Name
  3. QR code to contact info
  4. Bluesky Post 1
  5. Bluesky Post 2
  6. Bluesky Post 3
  7. call to action to share on Bluesky

It will use a 3000 mAh battery and all be contained in a 3d printed case meant to fit nicely in a shirt pocket. The T-Display has built in battery management for charging so the battery can just be directly connected and charged through the device with USB-C. The T-Display is less than $10 and a battery is even cheaper, so it is a great introductory device for playing with this kind of project. 

Video of operation is available on Bluesky.

Code on GitHub and print files on Printables (coming soon).

Additional build details and updates will be in the project logs.

badge-case-3dprint.stl

3d printed case for the lilygo t-display.

Standard Tesselated Geometry - 380.16 kB - 11/05/2025 at 22:50

Download

  • 1 × Lilygo T-Beam https://lilygo.cc/products/t-display-s3?variant=42351558590645
  • 1 × 3000 mAh Battery https://www.makerfocus.com/products/makerfocus-3-7v-3000mah-lithium-rechargeable-battery-1s-3c-lipo-battery-pack-of-4?srsltid=AfmBOoopaK-37heJh7GYtdwTIO3qZB2uGWMNHrsKtZyDEDmcelWjRPrE
  • 1 × 3D Printed Case Coming Soon

  • Screen Brightness

    JohnsonFarms.us10/18/2025 at 04:12 0 comments

    Since there are a couple of buttons on the T-Display I thought we could add a brightness adjustment. Just click the button and cycle through 4 brightness levels. 

    How It Works 

    1. PWM Control: Uses ESP32's LED Control (LEDC) peripheral to generate PWM signal on the backlight pin 4 
    2. Brightness Levels: 10%, 40%, 70%, and 100% mapped to PWM values 26, 102, 179, and 255 Button 
    3. Detection: Both buttons (GPIO 0 and GPIO 14) are configured with internal pullups (active LOW) 
    4. Debouncing: 200ms delay prevents accidental multiple presses 
    5. Cycling: Each button press cycles to the next brightness level and wraps around

    Code Snippets for Button Press Backlight Control

    1. Pin Definitions

    Add these button pin definitions at the top with your other pins:

    // Pin definitions
    #define PIN_LCD_BL 38     // Backlight pin
    #define PIN_BUTTON_1 0    // Boot button
    #define PIN_BUTTON_2 14   // Second button
    

    2. Global Variables

    Define brightness levels and state tracking:

    // Brightness control
    const uint8_t brightnessLevels[] = {26, 102, 179, 255};  // 10%, 40%, 70%, 100%
    const char* brightnessLabels[] = {"10%", "40%", "70%", "100%"};
    int currentBrightnessIndex = 3;  // Start at 100%
    unsigned long lastButtonPress = 0;
    const unsigned long buttonDebounce = 200;  // 200ms debounce
    

    3. Forward Declarations

    Add function declarations:

    void setBrightness(int index);
    void checkButtons();
    

    4. Setup - Initialize PWM Backlight

    Replace the simple digitalWrite() backlight control with PWM in your setup():

    void setup() {    // ... other setup code ...        // Initialize backlight with PWM    ledcSetup(0, 5000, 8);  // Channel 0, 5kHz, 8-bit resolution    ledcAttachPin(PIN_LCD_BL, 0);    setBrightness(currentBrightnessIndex);  // Set to initial brightness (100%)    Serial.print("Backlight initialized at ");    Serial.print(brightnessLabels[currentBrightnessIndex]);    Serial.println(" brightness");        // Initialize buttons    pinMode(PIN_BUTTON_1, INPUT_PULLUP);    pinMode(PIN_BUTTON_2, INPUT_PULLUP);    Serial.println("Buttons initialized");        // ... rest of setup ...
    }
    

    5. Loop - Check Buttons

    Add button checking in your main loop():

    void loop() {    // ... other loop code ...        // Check for button presses to adjust brightness    checkButtons();        // ... rest of loop ...
    }
    

    6. setBrightness() Function

    Set the backlight brightness using PWM:

    void setBrightness(int index) {    if (index < 0 || index >= 4) return;    ledcWrite(0, brightnessLevels[index]);    currentBrightnessIndex = index;
    }
    

    7. checkButtons() Function

    Handle button presses with debouncing:

    // Check for button presses and cycle brightness
    void checkButtons() {    unsigned long now = millis();        // Debounce check    if (now - lastButtonPress < buttonDebounce) {        return;    }        // Check if either button is pressed (active LOW with pullup)    bool button1Pressed = digitalRead(PIN_BUTTON_1) == LOW;    bool button2Pressed = digitalRead(PIN_BUTTON_2) == LOW;        if (button1Pressed || button2Pressed) {        lastButtonPress = now;                // Cycle to next brightness level        currentBrightnessIndex = (currentBrightnessIndex + 1) % 4;        setBrightness(currentBrightnessIndex);                Serial.print("Brightness changed to: ");        Serial.println(brightnessLabels[currentBrightnessIndex]);    }
    }

  • BlueSky API Pains

    JohnsonFarms.us10/18/2025 at 03:06 0 comments

    So connecting to BlueSky is super easy, and calling the API and pulling posts based off hashtags is no problem. Even pulling recent posts, which is what we are doing, is easy peasy. However, I kept having an issue and it would only pull a single most recent post, then the next two were 15 days old.

    So I took to the BlueSky website and did the search on the site and sorted by latest and got the same result. The interesting thing is that the first post it showed was in fact the most recent post, but the second was 15 days old, and the next was chronologically the next post to that one. The interesting thing was that the 15 day old post was pinned. After messing around a bit with trying to pull the posts in different methods with the API, it seems like somehow the pinned post messes up a few posts following it, then returns back to the actual "most recent" order. 

    Why is this? I don't know. It seems like it was only doing this to the pinned post plus 6 more. The pinned post was from seagl.org, which makes sense, but is a pain none-the-less. Thankfully this was a number of posts we could overcome. With the hardware limits of the ESP32 we could only pull 10 posts at a time, so basically we pull 10 posts and ignore any posts from @seagl.org and use the 3 most recent posts remaining. 

    So is this my ideal operation? No, but it does allow the tool to work and does still scoop up the community posts related to the event, so still a win in my book.

View all 2 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates