bookmark_borderPhysical Mute Button for Zoom Meetings

This is a big physical button you can put on your desk that will toggle your mute in zoom meetings, and if you hold the button down it leaves the meeting or ends it if you are the host.

It consists of a Digispark clone board (attiny85), a resistor, and a switch. The microcontroller acts as a keyboard with with just one button, and I’m taking advantage of the keyboard shortcuts built into the zoom app. The main thing that makes this work is the fact that CTRL+ALT+SHIFT brings focus to the meeting controls. This brings the zoom window to the front if you are a participant (sometimes I toggle mute with the button just to find the window), and it also works while you are sharing your screen. A short press sends ALT+A which toggles your mute state, and a long press sends ALT+Q then ENTER, which exits the meeting entirely.

Source code will be at the end of the post, it’s a slightly modified example from the digikeyboard library. I used the Arduino IDE – you’ll need to install the digistump boards through the board manager and also get the button library I used here: https://github.com/mathertel/OneButton. The wiring is very simple, it is just a momentary switch between GND and P0, and a 10k pullup resistor between 5V and P0 (this is not required at all in fact, so you can leave the resistor out).

I have created an instructable for this as well, a PDF copy is downloadable below and the link is: https://www.instructables.com/id/Zoom-Meetings-Physical-Mute-Button/

//Elliotmade 4/22/2020
//https://elliotmade.com/2020/04/23/physical-mute-button-for-zoom-meetings/
//https://www.youtube.com/watch?v=apGbelheIzg
//Used a digispark clone

//this will switch to the zoom application and mute it or exit on long press
//momentary button on pin 0 with pullup resistor

//https://github.com/mathertel/OneButton
//button library
#include "OneButton.h"

int button1pin = 0;

#include "DigiKeyboard.h"

//set up buttons
  OneButton button1(button1pin, true);

void setup() {
  // put your setup code here, to run once:


  //set up button functions

  button1.attachClick(click1);
  button1.attachLongPressStart(longPressStart1);

  DigiKeyboard.sendKeyStroke(0);
  DigiKeyboard.delay(500);
  
}

void loop() {
  // put your main code here, to run repeatedly:
  //monitor buttons
  button1.tick();
}


// This function will be called when the button1 was pressed 1 time (and no 2. button press followed).
void click1() {
  // this is generally not necessary but with some older systems it seems to
  // prevent missing the first character after a delay:
  DigiKeyboard.sendKeyStroke(0);
  
  // Type out this string letter by letter on the computer (assumes US-style
  // keyboard)
  DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT);
  DigiKeyboard.delay(100);
  DigiKeyboard.sendKeyStroke(KEY_A, MOD_ALT_LEFT);


} // click1


// This function will be called once, when the button1 is pressed for a long time.
void longPressStart1() {
  // this is generally not necessary but with some older systems it seems to
  // prevent missing the first character after a delay:
  DigiKeyboard.sendKeyStroke(0);
  
  // Type out this string letter by letter on the computer (assumes US-style
  // keyboard)
  DigiKeyboard.sendKeyStroke(0, MOD_SHIFT_LEFT | MOD_CONTROL_LEFT | MOD_ALT_LEFT);
  DigiKeyboard.delay(50);
  DigiKeyboard.sendKeyStroke(KEY_Q, MOD_ALT_LEFT);
  DigiKeyboard.delay(50);
  DigiKeyboard.sendKeyStroke(KEY_ENTER);

} // longPressStart1

bookmark_borderConway’s Game of Life in a spreadsheet

I saw this: https://hackaday.com/2020/04/13/john-horton-conway-creator-of-conways-game-of-life-has-died/, decided that I would try to write his game myself. This was just for fun and it isn’t optimized for anything really, but it might be useful to check out if you are getting into macros for Excel and need to read/update cells in a worksheet.

If you’re not comfortable downloading an .xlsm from (which is wise), the code below can just be pasted in an empty module. Make sure to name a sheet in your workbook “Life”, type in a number in cell B9 (or hardcode it), and add buttons to call the subs if you want.

The black cells are 1’s, white cells are 0’s. Might be interesting to tweak this so it generates QR codes and see where it takes you!

Option Explicit

'by Elliot (elliotmade.com) 4/14/2020
'Conway's game of life

'there is no input validation, and literally no optimization for anything
'wrote this purposely without looking at any examples other than a description of the rules, just for fun

'rules (from wikipedia):
'    Any live cell with two or three live neighbors survives.
'    Any dead cell with three live neighbors becomes a live cell.
'    All other live cells die in the next generation. Similarly, all other dead cells stay dead.

Dim xMax As Long
Dim yMax As Long

Dim x As Long
Dim y As Long

Dim xOffset As Long 'so it doesn't have to occupy the top and left cells
Dim yOffset As Long

Dim ws As Worksheet
Dim ticks As Long
Dim maxTicks As Long

Dim currentGrid() As Byte
Dim nextGrid() As Byte


Sub initialize()
'read in the initial state

xMax = 40
yMax = 40
ticks = 0

xOffset = 3
yOffset = 3

Set ws = Worksheets("Life")

ReDim currentGrid(1 To xMax, 1 To yMax)
ReDim nextGrid(1 To xMax, 1 To yMax)

For y = 1 To yMax
    
    For x = 1 To xMax
        currentGrid(x, y) = ws.Cells(y + yOffset, x + xOffset)
    Next x
Next y

maxTicks = ws.Cells(9, 2).Value


Debug.Print "Initialized"

End Sub

Sub clear()
    Call initialize
    ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).Value = 0
    Call initialize
    Call output
    Debug.Print "Cleared"

End Sub

Sub tick()
'really should do initialize if the variables aren't populated...

Dim countNeighbors As Integer

For y = 1 To yMax
    For x = 1 To xMax
        countNeighbors = 0
        'top neighbor
        If y > 1 Then
            countNeighbors = countNeighbors + currentGrid(x, y - 1)
        End If
        'bottom neighbor
        If y < yMax Then
            countNeighbors = countNeighbors + currentGrid(x, y + 1)
        End If
        'left neighbor
        If x > 1 Then
            countNeighbors = countNeighbors + currentGrid(x - 1, y)
        End If
        'right neighbor
        If x < xMax Then
            countNeighbors = countNeighbors + currentGrid(x + 1, y)
        End If
        
        'top left neighbor
        If x > 1 And y > 1 Then
            countNeighbors = countNeighbors + currentGrid(x - 1, y - 1)
        End If
        
        'top right neighbor
        If x < xMax And y > 1 Then
            countNeighbors = countNeighbors + currentGrid(x + 1, y - 1)
        End If
        
        'bottom right neighbor
        If x < xMax And y < yMax Then
            countNeighbors = countNeighbors + currentGrid(x + 1, y + 1)
        End If
        
        'bottom left neighbor
        If x > 1 And y < yMax Then
            countNeighbors = countNeighbors + currentGrid(x - 1, y + 1)
        End If
        
        If currentGrid(x, y) = 1 And (countNeighbors = 2 Or countNeighbors = 3) Then
            nextGrid(x, y) = 1
        ElseIf currentGrid(x, y) = 0 And countNeighbors = 3 Then
            nextGrid(x, y) = 1
        Else
            nextGrid(x, y) = 0
        End If
        
    Next x
Next y



currentGrid = nextGrid
Call output
ticks = ticks + 1

End Sub


Sub output()

Application.ScreenUpdating = False

For y = 1 To yMax
    
    For x = 1 To xMax
        ws.Cells(y + yOffset, x + xOffset).Value = nextGrid(x, y)
        If nextGrid(x, y) = 1 Then
            ws.Cells(y + yOffset, x + xOffset).Interior.ColorIndex = 1
            ws.Cells(y + yOffset, x + xOffset).Font.Color = vbBlack
        Else
            ws.Cells(y + yOffset, x + xOffset).Interior.ColorIndex = 2
            ws.Cells(y + yOffset, x + xOffset).Font.Color = vbWhite
        End If
    Next x
Next y

Application.ScreenUpdating = True
DoEvents

End Sub


Sub run()
Dim a As Long
'would be neat to end early if no changes occur between ticks...

Call initialize

If ticks = maxTicks Then
    MsgBox "Tick limit " & maxTicks & " reached"
    Exit Sub
End If

For a = 0 To maxTicks
    If WorksheetFunction.Sum(currentGrid) = 0 Then
        MsgBox "No live cells after " & ticks & " ticks"
        Exit Sub
    End If
    Call tick
Next a

End Sub

Sub randomize()
    Call initialize
    ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).FormulaR1C1 = "=RANDBETWEEN(0,1)"
    ws.Calculate
    ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).Value = ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).Value
    ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).Interior.ColorIndex = 0
    ws.Range(ws.Cells(1 + yOffset, 1 + xOffset), ws.Cells(yMax + yOffset, xMax + xOffset)).Font.Color = vbBlack
End Sub

bookmark_borderUSB Switch Mod

Working from home means two computers fighting over the same desk. KVM switches are not very affordable if you’re using anything more than VGA for your displays, but there are a bunch of cheap devices that will just switch your USB input devices and that is good enough for me. The only drawback is that most have the physical switch on the box itself, which means you need to have a whole bunch of USB cords sticking out of the thing in all directions within reach on your desk. I fixed this with some wire, a switch, two LEDs, and a piece of steel.

This works pretty well on the desk, and the block is nice and heavy so it stays put.