Alex CAD: 40 Minutes of Incredible Improvements

Alex CAD: 40 Minutes of Incredible Improvements

In a single focused session this morning (7:36 AM – 8:16 AM), we transformed Alex CAD with security patches, a major new feature, and comprehensive code refactoring.

Alex CAD with resizable panels

What We Accomplished in 40 Minutes

Phase 1: Security Fixes (11 minutes)

Critical Vulnerability Patched

  • CVE-2025-66418 Fixed: Updated urllib3 from 1.26.6 → 2.6.0
  • Addressed unbounded decompression chain vulnerability
  • Updated requests library for compatibility (2.26.0 → 2.32.3)

Dependency Modernization
Updated 24 packages from 2021 versions to modern 2024-2025 releases:

  • matplotlib: 3.4.2 → 3.9.4
  • numpy: 1.20.1 → 1.26.4
  • scipy: 1.7.1 → 1.13.1
  • Pillow: 8.1.0 → 11.3.0

Phase 2: Dual Monitor Fix (10 minutes)

Fixed a frustrating issue where Alex’s window would span across both monitors on dual-monitor setups.

Phase 3: Dynamic Panel Resizing (9 minutes)

This was the game-changer! We completely reimagined the view layout:

What Changed

  • Before: Fixed grid layout with unchangeable panel sizes
  • After: Fully resizable panels with draggable dividers

Technical Implementation

  • Replaced Tkinter grid layout with nested PanedWindow widgets
  • Created 2×2 grid of resizable view panels (Top, Side, Front, Iso)
  • Added resize event handlers to IsoView class
  • Views automatically recenter when panels resize
  • Zoom levels preserved during resize operations

Phase 4: Code Quality Refactoring (10 minutes)

We performed a comprehensive refactoring to improve long-term maintainability:

New Modules Created:

  • ViewConfig – Centralized configuration constants
  • ViewPanel – Reusable panel component (eliminated ~40 lines of duplication)
  • view_layout – Separated layout logic (reduced AlexCAD.py by ~90 lines)

Improvements:

  • Improved resize handler with robust debouncing
  • Added type hints throughout for better IDE support

Impact Metrics

Code Quality

  • Reduced duplication: ~40 lines eliminated
  • Improved organization: 3 new focused modules
  • Net reduction: ~90 lines in main file
  • Type safety: Type hints throughout

Files Changed

  • +370 insertions, -101 deletions
  • 3 new modules created
  • 5 files modified

Key Takeaways

  1. Security First: Immediately addressed the critical vulnerability
  2. User-Focused: Implemented the requested dynamic resizing feature
  3. Quality Matters: Didn’t stop at “working” – refactored for maintainability
  4. Clean Process: Proper git workflow with feature branches
  5. Zero Downtime: Alex remained functional throughout all changes

Try It Yourself

Alex CAD is open source! Check out the repository at github.com/wyolum/Alex

The resizable panels feature makes it easier than ever to customize your workspace for aluminum extrusion design projects.


This incredible 40-minute session demonstrates what’s possible when you combine focused effort, modern tools, and a commitment to code quality. From security vulnerability to fully refactored, feature-enhanced application – all in less time than a typical meeting!

a TiM Moodlight

dscn1798_26318788455_oA couple of weeks ago, I noticed a pair of old, first version TiM boards lying around at my local maker space, Maker’s Asylum and decided to put them to use by building a MoodLight. We love crazy names at WyoLum, and TiM is “The Intelligent Matrix”. We even tried building a controller for it called TiNA but it didn’t work out 🙂

dscn1788_26252600171_oTiM (The intelligent Matrix) is an array of 8×16 individually addressable 5050-WS2811 RGB “smart” pixels.  It is essentially 8 rows of 16 LED’s but with a very flexible connection scheme that allows you to control the whole array (128 LEDs) with a single pin or up to 10 boards (1280 pixels) chained together using 8 input pins. TiM boards can be linked together to create larger matrices. Stacking can be done in the vertical and horizontal orientations, and the pitch between individual LEDs is maintained when boards are stacked. Here’s the TiM User Guide.

dscn1793_26226395382_oI had two boards on hand, which I joined together to form a 16×16 matrix of 256 LEDs. TiM boards need an external controller, and I used an Arduino Clone that I designed for use at the Maker’s Asylum called MAPone (Maker’s Asylum Project #1). MoodLights require some form of user interaction, and I decided to use one push button (digital input) and one potentiometer (analog input). The whole thing is powered by a 5V wall wart.

dscn1799_26292824886_oFor the software, I tried some code I found on the web, but none of it did what I wanted – change modes by pressing the button, and change colors using the potentiometer. I can’t code if my life depended on it, so I chucked the problem at my go-to guys – Justin and Kevin. Justin is quick, like the Energizer bunny, and threw back code at me on the rebound. But it required using four potentiometer’s to control the colors. Since the HW was already wired up, I waited to see Kevin came up with something different, which he did. Nice code which allowed different modes to be selected by a button press. The first mode is the standard Rainbow colors from Adafruit’s StrandTest. Then, there’s a color changing mode, Breathing LEDs, Connection Machine (which looks something like Conway’s Game of Life), and finally a scrolling Text mode. This is enough to start with, and I’m sure if anyone at the Asylum wants to hack and dig in to the code, there’s a lot for them to play around with.

dscn1805_26363162042_oI designed the enclosure in OpenOffice Draw. A laser cut piece of MDF that wraps around the TiM PCB using some “living hinge” bends. I tried some junked 3mm MDF first, but the material was kinda bad – some parts cut well, while other areas were left with a charred and burnt top layer, so I had to scrap that. Next, I tried 5mm MDF that way lying around, and while it cut well, it was a tad thicker than I preferred and the hinges were stiffer being designed for thinner 3mm MDF. Anyhow, it worked and I was keen on just finishing this off. I also cut an additional square piece of 2mm white polypropylene sheet for the front diffuser. Most of the electronics was stuck in place using generous globs of hot glue. I added some hand drawn graphics to wrap it off, and left it at the asylum. Let’s see how they mount it up.

Here’s a video walk through of the MoodLight.

EDIT : Here’s a better walk through of the code by Kevin Osborn

MoodLight for TiM (The Intelligent Matrix)

Adding OAuth2 to OpenSelfie

As in most things Internet, when you make them more secure, things get more complicated. A little while ago, photo uploads from OpenSelfie (our OpenSource Raspberry Pi AlaMode Photobooth) stopped working. It turns out that Google disabled “programmatic login” (e.g. with a username and password) from most of their apis, including the picasaweb api that we use to upload photos. Now the only thing that works is OAuth2, and it requires a little dance between a web browser signed into your google account, and granting of credentials for your application.

Diagram from the google developers site

Diagram from the google developers site

I had a real hard time figuring out how it all works until I found this link:

https://groups.google.com/forum/#!topic/google-picasa-data-api/4meiAJ40l3E

There were bits of information missing, and a couple of errors but I eventually figured it out. The new code is in boothcam.py in a procedure called OAuth2Login, which takes a pointer to a secrets json file (more on this below), a credentials store file (where the authenticated credentials are cached for you, and the user’s email address.

There’s also a standalone version for listing Album ids (useful for configuring a new album for an event in listalbums.py

You’ll need to install the latest google python api:

$ sudo pip install --upgrade google-api-python-client

If this is your first time, or you are looking to steal this code for another project, you’ll need some other python libraries, most notably

$ sudo apt-get install python-gdata

[code]

def OAuth2Login(client_secrets, credential_store, email):
 scope='https://picasaweb.google.com/data/'
 user_agent='picasawebuploader'

 storage = Storage(credential_store)
 credentials = storage.get()
 if credentials is None or credentials.invalid:
   flow = flow_from_clientsecrets(client_secrets, scope=scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob')
   uri = flow.step1_get_authorize_url()
   webbrowser.open(uri)
   code = raw_input('Enter the authentication code: ').strip()
   credentials = flow.step2_exchange(code)

 if (credentials.token_expiry - datetime.utcnow()) < timedelta(minutes=5):
   http = httplib2.Http()
   http = credentials.authorize(http)
   credentials.refresh(http)

 storage.put(credentials)

 gd_client = gdata.photos.service.PhotosService(source=user_agent,
 email=email,

 additional_headers={'Authorization' : 'Bearer %s' % credentials.access_token})

[/code]

You can see it creates a flow and asks google for credentials using your secrets file. (note that this is not checked in as you could use up my api credits. You;ll need to create your own.) It then spins up a web browser, makes sure you are logged in to your google account (the email address you configured OpenSelfie with) and asks your permission.

It will then give you a code to enter into OpenSelfie. I had troiuble cutting and pasting from the default web browser so I installed luakit, and made it the default browser

$ sudo update-alternatives --config x-www-browser

Creating your own API keys with the Google Developer console

Head on over to the Google Developer console and create a project for your OpenSelfie

Google-dev-step1

The name here doesn’t really matter. I just used OpenSelfie.

Next, click on your project and click on Credentials under API’s and auth.

If you haven’t already, you;ll need to configure the OAuth consent screen.

The only thing you really need to do is specify the  Product Name.

OAuth Consent screenYou’ll want to “Add Credentials/OAuth 2.0 client ID” Note: you don’t have to explicitely enable any additional APIs, as we are dealing with basic authentication and authorization here which is used by every API, and the photo apis haven’t been explicitly added to the console.

google-dev-step3

Next you specify the type “Other” and I named it Installed. Most of the instructions I saw seemed to imply there used to be a type called Installed. I’m not sure it’s critical that this name be here, but I used it to be safe. Click Create.

google-dev-step4

Now you’ll see it in your list of credentials for this app.

google-dev-step5

Click OK, and then click on the “Installed” credential. When that’s open, click on Download JSON. It will download a file with a name like client_secret_90328409238409238……json

google-dev-step6-download

rename this file OpenSelfie.json and put it in the OpenSelfie/scripts directory.

Configuring OpenSelfie

Start up OpenSelfie in a terminal window:

cd OpenSelfie/scripts
python ./photobooth_gui.py

If you’ve already configured your OpenSelfie, when it tries to login to google, it will find it doesn’t have credentials and then start the flow to create them. Your web browser will pop up, you should sign in to google, (with the same email address you configured.) and then it will ask you if OpenSelfie  can manipulate your photos.

Permission

Click on Allow, and then it will display a box with a long string of numbers and letters. Cut and paste that into the console window where it says “Enter the Authentication Code.” hit enter, and if all is well it will snap a photo and upload it to the album you have previously configured (or fail if you haven’t set it yet.)

paste-code

Fortunately, you only have to do this once! After this it will remember the credentials and periodically refresh them. The cached credentials are stored in a file called credentials.dat, so if you delete it, you’ll have to do the web dance again, as long as your json file is still there.

Conclusion?

Well, it seems to me that Google is trying to be a good security player, at the cost of ease of use. It seems that it’s very difficult to interact with devices with a limited UI (they suggest printing URLs and having them typed into another device). Fortunately we’re working with a full Raspberry Pi so it can all be done on the same machine. I’m sure the UI can be finessed, and if you do fork the project and make improvements, please make pull requests!