Power Button In Action

This weekend I focused on getting the GB LED in my power button to work. I needed to use an SPI PWM board from Adafruit to control the LED. You can see it working above. When the device is on, the light is green. Hold the button down for 5 seconds and it turns purple, signaling that when you release it the device will power down. When it powers down the light turns (and stays) red.

I have detailed instructions on using the PWM with a Raspberry Pi. A couple of highlights (mistakes) that didn’t make it into the post are worth noting here.

First off, I didn’t do a great job soldering the header pins to the board. I had too much solder on some of the pins, which resulted in a sphere on the end of the board that didn’t make enough contact to keep the pin firmly attached. Which is to say the pins fell out. Next, I realized that I had soldered the header on to the output side of the board, not the input, meaning that it was ready for me to daisy chain on another board… but that I couldn’t use the current board without soldering the other side on. A textbook case of Murphy’s Law.

All of these soldering mistakes meant it was time to break out the soldering iron and fix my mistakes. I resoldered the bad pins, and added another header to the CORRECT side of the board. While I was there I added a male header to expose the voltage pinouts. One convenient mistake I had made weeks ago was soldering a female jumper wire to the voltage pin on my power LED. With the new male header on the board, it was easy to wire this up.

Speaking of wiring, I used some rainbow tape to on the red, green, and blue jumpers coming from the power LED to keep them organized, and then plugged them into my breadboard, connecting them to the PWM board. From there, wiring up the Pi to the board was pretty simple. I used some more rainbow tape to keep those wires in order and make it easy for me to connect and disconnect the board entirely.

Next it was time to dip into Python to integrate the LED to my existing volume controller app. The code can be found in my Day 7 pull request. The majority of went into a dedicated RgbLed class. It doesn’t expose a lot of the features, but enough for now.

Pictures

Prototyping with the Pi

Moving on to wiring directly to the Pi

PWM Module Wired Up

Here it is fully wired and turned on with the lid off

Fully Wired

Here are some quick notes on getting the 12 channel 16-bit PWM driver from Adafruit. (It’s not that different from the 24 channel version) As usual, Adafruit’s documentation was super useful, and they even had a page about getting it to work with the pi.

What is a PWM Driver?

A Pulse Width Modulation driver allows you to either connect a whole bunch of regular LEDs with just a few pins (and the PSI protocol). The 12 channel driver can support 12 LEDs. Additional drivers can be daisy chained on allowing near limitless LEDs. If regular LEDs don’t interest you, you can use 3 channels to drive a single RGB LED (for 4 total per module).

Software Setup

  1. Enable SPI. (
    1. Run sudo vim /boot/config.txt
    2. Ensure dtparam=spi=on is uncommented (or add it)
    3. Reboot with sudo reboot
    4. Verify it worked with ls /dev/spi*
  2. Python Dependencies
    1. Install python-venv with sudo apt-get install python3-venv
    2. Install pip with sudo apt-get install python3-pip
    3. Create a virtual environment for your project with python3 -m venv pvenv
  3. Install Circuit Python on the Pi
    1. Install Circuit Python with pip3 install adafruit-blinka
    2. Install the Adafruit library pip3 install adafruit-circuitpython-tlc59711
    3. Verify everything works by going into the python interpreter and importing the new packages (you shouldn’t get any errors)
       import board
       import busio
       import digitalio
       import adafruit_tlc59711
      
  4. Optionally save your imports with pip3 freeze > requirements.txt

Hardware Setup

  1. Optionally follow the instructions on Adafruit’s site to solder on headers so the module can be plugged into a breadboard.
  2. Optionally solder on headers to the voltage pins on the board. This helps wiring when it’s inconvenient to just wire the LED’s leg directly to power.
  3. Wire it up! Use the below table or image. Make sure that you orient the board correctly and that you’re plugging into the input side and not the output side

Wiring Diagram

The table goes from the top down on the pins on the left side of the module. When there are multiple pins to choose from, I have bolded the pin that I used.

PWM (TLC59711) Raspberry Pi Pi Pin Number
GND Ground 6, 9, 14, 20, 25, 30, 34, or 39
VCC 5v Power 2 or 4
V+ 5v Power 2 or 4
CI Serial Clock (SLK) 17
DI MOSI 19

After this, plug an RGB LED in to any of the RGB pins on the board with the longest pin going to one of the 12 voltage pins.

Testing it

Fire up a python3 REPL and import everything from above and then start turning on some LEDS:

import board
import busio
import digitalio
import adafruit_tlc59711

spi = busio.SPI(clock=board.SCK, MOSI=board.MOSI)
rgb = adafruit_tlc59711.TLC59711(spi)

# Full Red, Green, or Blue (mix/match as much as you like)
rgb[1] = (65535, 0, 0)
rgb[1] = (0, 65535, 0)
rgb[1] = (0, 0, 65535)

rgb.b1 = 32768
rgb.g1 = 16384
rgb.r1 = 8192

rgb.red_brightness = 10
rgb.green_brightness = 10
rgb.blue_brightness = 10

Today was a simple day. I wired up the on/off button. Pressing it when it’s powered off powers it on. Holding it while it’s on starts a clean shutdown. My next step is to use the LED in the button to provide status (shutting down, on, release to turn off, etc).

I’ve wanted to have a proper IDE environment on my Windows machine that can execute code on my Raspberry Pi. Turns out that there’s a new VS Code extension that purports to do just that. Except if you read the fine print it currently only supports an x86_64 Linux-based OS.

But still, it’s worth keeping an eye on the Remote SSH extension. It’s new as of a few days ago and I expect that they’ll make improvements and allow more environments over time.

In the mean time, I’m trying out SSH FS, which allows you to treat an SSH host as a workspace. By default it treats the host’s entire file structure as your workspace, so make sure you specify a root. It’d be more ideal if you could run commands directly on the host. But you can always just ssh to the host in Code’s terminal.

Once the extension is installed, run the command SSH FS: Edit configuration to add a configuration. Once you’ve configured it (see below), run the command SSH FS: Connect as Workspace folder and select the configured host.

"sshfs.configs": [
  {
    "host": "piz01",
    "label": "piz01 - PiProject",
    "name": "ssh_fs",
    "privateKeyPath": "$HOMEDRIVE$HOMEPATH/.ssh/id_rsa",
    "root": "~/PiProject",
    "username": "pi"
  }
]

Update:

After working with this for a few hours it proved to be unreliable. When it was working it was great, but there were plenty of times when trying to set up the configuration was flaky. This resulted in not always being able to read the configuration which meant that I couldn’t connect.

In the end it was easier to just remote in to the pi and use vim.

Not only am I late with this status report for last Sunday. I finished getting everything wired up and cleaned up my desk with 3 minutes to spare before the season premier of Game of Thrones. There was no chance I was going to write up a status report at that point. Since then I’ve done more work so it’s not really a true status for day 4. Let’s call it 4.5.

Software

I decided to shelve any work towards getting the BlueTooth connectivity to work for the time being. I was putting a lot of effort into that without a lot of results. My goal for an MVP is now to get a box that has a volume knob that works. The quickest route without too much throwaway work is a device that makes rest calls to a configured laptop running a webservice that handles the volume control. This will let me concentrate on getting the electronics up and running and the physical box built.

Towards that, the first thing I did was refactor out the SimpleButon and SimpleRotary scripts I had from last week into python classes and use them in a python script that calls a webservice.

With that done, I quickly transferred the proof of concept to a Pi Zero W. Or at least I tried to. For whatever reason, whenever I tried to do a git pull the command line hung. After some googling I tried a last ditch attempt of just updating the OS with

sudo apt-get update
sudo apt-get dist-upgrade

Surprisingly, that actually did the trick. Now my only issue is that I never installed the prereqs on the Zeros. So a few apt-gets later, and I’m back in business.

sudo apt-get -y install python3-rpi.gpio
sudo apt-get -y install python3-venv

Once the code’s running on the Pi, I have to figure out how to get it to run whenever it stats. Some more googling and I find Pi’s documentation on rc.local.

sudo vim /etc/rc.local

Hardware

Coding. Done. Linux administration. Done. Next up is actually making the box.

A few weeks ago I picked up a black plastic enclosure from Tinkersphere. To make it easy to expand in the future, I used the glue backing on the back of an extra mini breadboard to affix it to the bottom of the case. I had to take the power rails off first so it would fit in the slot.

Bottom of the enclosure with Pi mount and breadboard

Next, I use Sugru on the bolts of my PiBow case to affix it to case. I used the full assembled case to ensure that there was sufficient space for the bolts, but removed disassembled the case and left only the bottom plate and the bolts while it set. I’m actually pretty surprised it worked so well.

The Sugru is solid enough that it didn’t ooze anywhere it wasn’t supposed to. I kind of want to try the same thing with a glue gun since it’s a little cheaper and easier to have on hand (my Sugru was technically expired…). I just don’t think it’ll work as well.

Close up of Pi mount

Now on to the top. I used a 15mm Forstner bit to drill a hole in the top for the power button. Then I used a 16mm bit to widen it because I misread the size on the button.

I used standard drill bits to make a 5/16” hole in the side for the rotary encoder. This time I started with a quarter inch bit on Sunday, and then had to buy the 5/16” bit during the week. It was a perfect fit with the additional 1/16” inch.

Enclosure with holes for power button, encoder, and power cord

I couldn’t figure out how to cleanly get a small hole for the power USB cable in the bottom of the case. I went drilling a hole near the edge and then using my Leatherman to whittle the notch to the desired size. Worked well enough, but it wasn’t as smooth as the other holes.

Power cord hole

I needed to get rid of the ridges on the interior side for the encoder to sit flush and extend far enough out. I didn’t have any better ideas so I grabbed a drill bit a little larger than the space between the grooves. I used that to drill out some of the ridges and then went in with the blade of my Leatherman to remove the rest. Next the file on the Leatherman helped smooth out any uneven ridges. Not super pretty, but it worked; the encoder sat flush.

Hole for encoder with ridges filed out

Speaking of the encoder, I was concerned about how I was going to attach the wires to it in reliable way. I didn’t have any better ideas, so I figured now was a good enough time as any to learn how to solder.

Including burning myself (twice), it went much better than I expected. I cut off one end of some jumper wires and soldered them on to the encoder and then button. I was on such a roll I even soldered the head on to a TLC5947 from Adafruit. I plan on using that in my next step to power the RGB light ring on the button.

Solder points for encoder Soldered encoder and jumper wires Push button Push button

The button has a RGB LED in it so I color coded the wires. Red for the red channel, green for the green, and blue for the blue. The yellow and orange are for the button itself.

Color coding on soldered push button

During the week, a heat gun I had ordered arrived so I slipped some plastic shrink around all of my soldered connections and then larger ones to group the wires together a bit.

Thanks to some advice from a friend, I picked up some heat resistant gloves on Amazon and didn’t burn myself with the heat gun at all.

Soldered encoder with plastic shrink

With all the wires soldered in place. I just have to assemble everything again. I screwed in the button, and glued in the encoder. Then I remembered that the encoder had a bolt as well, so I attached that and it was much more secure.

I upgraded the knob on the encoder to a nice metal 1” job from Adafruit. It has a nice feel to it. Just needed a 2mm hex wrench to secure it in place. Which I got today, just in time.

Enclosure with button and enclosure

Now that the Sugru has had enough time to set, I reassembled the Pi case . . .

Mounted Pi

. . . and plugged it into the breadboard.

Wired up Pi

I had color coordinated the wires for the Pi with the rotary encoder, so it was easy to remember what goes where.

Wired up encoder

For now, I’m plugging the power button in randomly to the breadboard just so the wires aren’t loose. My next step is to get that bit working.

Everything wired up

And voila.

Fully assembled

I was surprised by home much I was able to get done in one day. It still doesn’t really do much except call a webservice that just logs that it was called, but it’s a start.

Here’s all the code on github as of this posting.

Pi, Raspberry Pi comments edit
  1. Login (username: pi password: raspberry)
  2. Run the wizard: sudo raspi-config
  3. Reset password (1)
  4. Set hostname (2, N1)
  5. Setup Wifi (2, N2)
  6. Enable SSH (5, P2)
  7. Change timezone (4, I2)
  8. (alternate method) Connect to WiFI
    1. Edit the supplicant file:
      sudo vi /etc/wpa_supplicant/wpa_supplicant.conf`
      network={
       ssid="testing"
       psk="testingPassword"
      }
      
    2. Reset the interface and test it
      wpa_cli -i wlan0 reconfigure
      ifconfig wlan0
      
  9. Fix keyboard layout
  10. sudo vi /etc/defaults/keyboard
  11. Set XKBLAYOUT="us"
  12. Reboot
  13. Verify by typing a "
  14. Updates
    sudo apt-get update
    sudo apt-get upgrade
    
  15. Install Softwares
    sudo apt-get install vim screen tmux
    sudo update-alternatives --config editor
    
  16. Install .Net
  17. Generate new SSH host keys (if you are using an image used by another Pi)
  18. sudo ssh-keygen -b 4096 -h -f /etc/ssh/ssh_host_rsa_key

I recently bought a Raspberry Pi Zero W. I immediately had problems using it. Here are a couple of useful (and useless) things I tried. Adafruit has a great tutorial on what to do when you think your pi is dead as well.

First I bought another one (they are so cheap) just in case the first was DOA. No dice. Then I tried buying a USB adapter for my mouse and keyboard hoping that it only boots to video if there are input devices (long shot I know, but I was going to need the adapter anyway). Nope. Then I tried dropping an empty file named SSH into my boot directory on the SD card and enabling WiFi through a wpa_supplicant.conf file. I still couldn’t ping the device, let alone SSH in. After that failed I tried using PiBakery to create a new image that had everything baked in. It really wasn’t much different than what I had done. I bought a new SD card hoping it was a compatibility issue. Again, I knew I was going to need one anyway, but it didn’t help.

I was able to verify that it did in fact work by taking out the SD card and plugging it directly into my PC via the USB port (not the charge port, but the port on the left for peripherals). It showed up under Device Manager as BCM2708 Boot. At least I knew it wasn’t full dead yet.

In the end, the issue was that I was trying to connect to my 5GHz network (Pi Zero W’s don’t support that) and that my HDMI cable was busted. The network issue was much easier to diagnose once I had a monitor plugged in.

Pi, Raspberry Pi comments edit

Putting together the Raspbery Pi Zero W PiBow is really easy if you know how. Even if you don’t, you can figure it out. But it’s easier if you know the order the pieces go together.

Layout the pices

Layout the pieces

Step 1

Step 1

Step 2

Step 2

Step 3

Step 3

Step 4

Step 4

Step 5

Step 5

Step 6

Step 6

Step 7

Step 7

Day 3 was a bit of a loss. I spent a few hours (to no avail) trying to figure out what’s wrong with my Pi Zeros. I’m hoping the answer is secretly “nothing” and that my HDMI cable is bad and I’m not configuring the wifi correctly. After that I futzed with some reading about bluetooth and D-Bus. I think D-Bus may not be what I need going forward. Looking further into existing bluetooth libraries for connecting as a keyboard.

To make sure I got progress on something, I spent the last hour and a half of the day learning how to use a rotary encoder. The basic principle is that there are two contacts in quick succession that are connected and disconnected for every notch you rotate the device knob. If you track which contact was connected first, then you know which direction it was turned. The source code is pretty straight forward.

encoder on a breadboard

On day 2 I started complaining to a friend that I kept burning out my GPIO ports and that they didn’t work properly. He helpfully suggested that I may not have had the pins plugged in to the correct spots.

After telling him that there was no way that I was plugging the things in wrong since I was using the Adafruit Pi Cobbler, I took a closer look and realized that I had plugged the wrong end of the cable into the Pi. The gray stripe needs to be near the bottom of the board, where the SD card reader is. I then took a Sharpie and labeled the ends of the cable so I don’t make this mistake again in the future. Or at least to make it less likely.

Mystery solved.

Pi, Raspberry Pi comments edit

Knowing Your Pi

The following commands are useful for getting detailed info about the Pi build. They were found on raspberrypi-spy.co.uk

pinout

> pinout
,--------------------------------.
| oooooooooooooooooooo J8     +====
| 1ooooooooooooooooooo      P | USB
|  Wi                     ooo +====
|  Fi  Pi Model 3B+ V1.3  ooE    |
|        ,----.               +====
| |D|    |SoC |               | USB
| |S|    |    |               +====
| |I|    `----'                  |
|                   |C|     +======
|                   |S|     |   Net
| pwr        |HDMI| |I||A|  +======
`-| |--------|    |----|V|-------'

Revision           : a020d3
SoC                : BCM2837
RAM                : 1024Mb
Storage            : MicroSD
USB ports          : 4 (excluding power)
Ethernet ports     : 1
Wi-fi              : True
Bluetooth          : True
Camera ports (CSI) : 1
Display ports (DSI): 1

J8:
   3V3  (1) (2)  5V
 GPIO2  (3) (4)  5V
 GPIO3  (5) (6)  GND
 GPIO4  (7) (8)  GPIO14
   GND  (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND
GPIO22 (15) (16) GPIO23
   3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND
 GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8
   GND (25) (26) GPIO7
 GPIO0 (27) (28) GPIO1
 GPIO5 (29) (30) GND
 GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
   GND (39) (40) GPIO21

model

> cat /proc/device-tree/model
Raspberry Pi 3 Model B Plus Rev [email protected]:~ $

cpuinfo

> cat /proc/cpuinfo
processor       : 0
model name      : ARMv7 Processor rev 4 (v7l)
BogoMIPS        : 38.40
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd03
CPU revision    : 4

// snip.  It's a 4 core processor,
// so the above is repeated 3 more times

Hardware        : BCM2835
Revision        : a020d3
Serial          : 00000000e296b315

I’ve made some interesting progress in my current poject with my Raspberry Pi.

After following a walkthrough, I was able to connect my Pi to my Windows laptop as if it were a Bluetooth keyboard and forward all keystokes from the Pi’s keyboard to my laptop. In fact, I’m writing this status report on with my Pi’s keyboard on my laptop.

The only issue with the walkthrough is that it’s missing one dependency, before getting started python-gtk2 needs to be installed:

sudo apt install python-gtk2

I’ve made a copy of the sample code in my own repo so I can start to play with it.

Next up is to go through the follow up post and move leverage GPIO (buttons!)

Pi, Raspberry Pi comments edit

After starting on my Raspberry Pi project, I realized that the Raspberry Pi 2 doesn’t have onboard Bluetooth. I could either buy a Bluetooth dongle or switch to a Raspberry Pi 3. And since I have a Raspberry Pi 3 in my drawer and not a Bluetooth dongle, I decided to start over on my 3. So now I’m taking notes on exactly what I need to do in order to get a Pi up and running.

  1. Download the latest version of Raspbian. For this project I elected to have the version with a desktop. Estimated download time is about 10 minutes.
  2. Install etcher from an admin shell with cinst -y etcher. Estimated downloaded time is about 2 minutes.
  3. Open etcher. If it’s not on your desktop, then hit the start button and type in BalenaEtcher
  4. Pick the file you downloaded file from step 1, and flash it to an SD card.
  5. Insert SD card into Pi and boot it up. The initial boot takes a little longer than normal.
  6. Go through the onscreen Welcome Wizard
    1. Change the password (remember to write it down)
    2. Connect to WiFi. This will also fix the date/time.
    3. Run system updates. This may take
    4. Reboot
  7. Fix any mouse lag issues, if they exist
    1. sudo vi /bot/cmdline.txt
    2. Add ` usbhid.mousepoll=0` to the end of the line
    3. Reboot (this can be done while the Updates are being installed)
  8. [Optional] Change the host name (this comes in handy if you have multiple Pis and are using RSA keys)
    1. `sudo vi /etc/hostname
    2. Reboot (this can be done while the Updates are being installed)
  9. Enable SSH on the Interfaces pane of the Raspberry Pi Configurator (accessible from the Pi menu)
  10. Copy public key to the Pi
    1. On the new Pi: mkdir .ssh
    2. On the local machine: scp id_rsa.pub [email protected]:.ssh/
    3. On the new Pi: cat .ssh/id_rsa.pub >> .ssh/authorized_keys

Optional

  1. Install vim
    1. sudo apt-get install vim
    2. sudo update-alternatives --config editor
  2. Install screen
    1. sudo apt-get install screen
  3. Install VS Code - (Full Article)
    1. Install it
       sudo -s
       . <( wget -O - https://code.headmelted.com/installers/apt.sh )
      
    2. Uninstall it and install it again! As of this writintg there’s a known issue with the current build. The easiest workaround is to just install an older version. The last command here tells the system not to upgrade VS Code when you ask it to upgrade other things. ```bash sudo apt-get remove code-oss sudo apt-get install code-oss=1.29.0-1539702286 sudo apt-mark hold code-oss
  4. Login to github
    1. Create a personal access token
    2. Configure git with your name, email, and tell it to stop asking for passwords
       git config --global user.name "Josh Quintus"
       git config --global user.email "[email protected]"
       git config --global credential.helper store
      
    3. Do a git push and use the access token as your password. You can forget it from here on out.

Back it up

Now that everything is set up just-so, it’s worth creating a backup so that we don’t have to do all of this ever again.

  1. Install Win32 Disk Imager
     choco install -y win32diskimager.portable
    
  2. Start up Disk Imager
     Win32DiskImager.exe %HomeDrive%\%HomePath%\Desktop\buttons.img
    
  3. There will be two devices that you can pick in the dropdown. Select the one that you can navigate to in Windows Explorer
  4. Press the Read button
  5. Wait
  6. [Optional] Zip it up. This took the file down from about 32GB (the size of the disk) to about 2GB

I want to easily connect to my Raspberry Pi from my Windows machine, specifically from inside my preferred terminal, ConEmu. First we’ll need to set up some SSH Keys on the Pi(although if you’re comfortable keeping your password inside some configuration files, this is actually optional), set them up on the Windows box, and then configure ConEmu and your environment.

Setting up SSH Keys

On your Pi:

  1. Run ssh-keygen and follow the prompts, accepting the defaults
  2. Save the key file to /home/pi/.ssh/id_rsa (just press enter, as this is the default)
  3. Type in your passphrase (you can elect to keep this empty but it means that anyone who gets the private key will be able to log on to your machine. So consider if this is really what you want. For me, I don’t really care if people can log in to my Pi for now, so I’m ok with an empty passphrase
  4. Configure sshd
  5. sudo vim /etc/ssh/sshd_config and ensure you have these values RSAAuthentication yes PubkeyAuthentication yes PermitEmptyPasswords yes
  6. Copy the private key (/home/pi/.ssh/id_rsa) to your Windows machine. You can just SSH in to the Pi using the username and password, cat` the file and copy them from the console. Save it to your home directory.

On your Windows Box

Starting with Windows 8 (I think?), Windows started shipping with a SSH client built in. Which means, as good as it was, there’s no need to download and install PuTTY anymore.

  1. Test the connection
  2. ssh -i %HomeDrive%%HomePath%\id_rsa [email protected]
  3. You should now be logged in to your Pi

Integrating with ConEmu

For convenience I added the following alias to my cmd init file. It allows me to just type pi at the command line and be logged into my Raspberry Pi immediately.

DOSKEY pi=ssh -i %HOME%\id_rsa [email protected]

Next I added a task in ConEmu so I can open a new tab directly into the Pi.

  1. Open the settings and go to Setup/Tasks (or just press `Alt-Win-T)
  2. Press the + button on the bottom left and fill in these values
  3. Name (first box): Pi
  4. Commands (large box): ssh -i c:\users\joshq\id_rsa [email protected]
  5. Hotkey [Optional]: Alt-P
  6. Press Save settings (or just hit the escape key)
  7. Try out the shortcut by pressing Alt-P

DIY, Pi, Raspberry Pi comments edit

I’m starting to work on a project on a Raspberry Pi. I’m starting with a Pi 2 that already has an older version of the Pi os installed on it (I don’t even remember what one).

The first issue that I came across was that the Amazon Basics mouse was too slugish. After googling for a bit I came up with the solution that I needed to make an edit to a config file (becuase of course the first thing I needed to do was edit a config file because Linux) and then reboot the system.

sudo vim /boot/cmdline.txt
sudo reboot

Append the following to the end of the line (separated from the last entry with a space).

usbhid.mousepoll=0

zsh comments edit

In order to loop over all the files in a given directory and run a different command on each of them in zsh:

for file in ~/folder/*; gpg $file

Coding comments edit

It can be tricky to know what you can and can’t use when looking at free libraries. The following is a quick rule of thumb for Open Source Licenses.

Good

Bad

Some licenses are explicitly not OK to use. For example, none of the copyleft licenses can be used in a closed source project. The following list is not exhaustive. Just because a license is not on the list does not automatically mean that it can be used.

Dual Licenses

It is possible for a project to have more than one license specified. Unless specified otherwise in their licensing, all clauses from all licenses may apply. This means that, to be safe, each license to be on the compatible with the consuming project.

Other Licenses

Any other license must be evaluated on a case by case basis.

More Information

The Open Source Initiative has lots of useful information about OSS licensing. Choose A License does a great job of breaking down the most common licenses comparing the differences between them.

coding comments edit

These are the general rules and guidelines I use when developing. As with most rules, there are exceptions to all of these.

Code Quality

  1. Prefer composition over inheritance
  2. Small classes and small methods. Anything over 30 lines for a method is a smell, over 100 is a NO
  3. Pay attention to code readability. It’s been pointed out before, but other developers will have to read your code. And “other developers” includes you in 3 months. You are writing for them, not for the compiler. If they can’t understand what’s going on, you haven’t done your job.
  4. Comments get out of date very quickly so only add them in cases where they bring true value, as opposed to making them a supplement for code that has poor readability. This typically means that you shouldn’t be commenting on what your code does. Whoever is reading it should already know what it does. Comments should elucidate why your code is doing what it does. You may have had to write the code in a non-obvious way to avoid a bug. Explain that.

C# Coding Style

For most of my career I’ve been a C# developer. So my more specific rules apply to that. Despite that, many of them can be generalized to other domains. These rules were adapted and inspired from the corefx project, the general rule is “use Visual Studio defaults”.

For non code files (XML, JSON, etc.) my best guidance is consistency. When editing files, keep new code and changes consistent with the style in the files. For new files, it should conform to the style for that component.

  1. Use Allman style braces, where each brace begins on a new line. A single line statement block can go without braces but the block must be properly indented on its own line and it must not be nested in other statement blocks that use braces (See issue #381 for examples – read the resolution, not just the first comment).
  2. Use four spaces of indentation. No tabs. Never tabs.
  3. Use _camelCase for internal and private fields and use readonly wherever possible. Prefix instance fields with _. When used on static fields, readonly should come after static (i.e. static readonly not readonly static).
  4. Avoid this. unless absolutely necessary.
  5. Always specify the visibility, even if it’s the default (i.e. private string _foo not string _foo). Visibility should be the first modifier (i.e. public abstract not abstract public).
  6. Namespace imports should be specified at the top of the file, outside of namespace declarations and should be sorted alphabetically.
  7. Avoid more than one empty line at any time. For example, do not have two blank lines between members of a type.
  8. Avoid spurious free spaces. For example avoid if (someVar == 0)..., where the dots mark the spurious free spaces. Consider enabling “View White Space (Ctrl+E, S)” if using Visual Studio, to aid detection.
  9. Use language keywords instead of BCL types (i.e. int, string, float instead of Int32, String, Single, etc) for both type references as well as method calls (i.e. int.Parse instead of Int32.Parse). See issue #391 for examples.
  10. Use ALL_CAPS to name all constant local variables and fields. The only exception is for interop code where the constant value should exactly match the name and value of the code you are calling via interop.
  11. Use nameof(...) instead of "..." whenever possible and relevant.
  12. Fields should be specified at the top within type declarations.
  13. When including non-ASCII characters in the source code use Unicode escape sequences (\uXXXX) instead of literal characters. Literal non-ASCII characters occasionally get garbled by a tool or editor.
  14. One class per file. When we have a generic and non-generic definition of a simple class, they can be in defined in the same file.
  15. Member fields must be private (who creates public fields anyway?)
  16. CamelCasing of all variable and method names; methods and properties start with a capital
  17. Avoid #regions
    • Specifically included
      • Regions around common sections of code. e.g. regions around all fields or properties
    • Exceptions
      • Regions around particularly long constants or literals
      • Regions around auto-generated code
  18. Only capitalize the first letter in an abbreviation/initialization when using it in a name. For example:
    • DbPool() ✔️
    • DBPool()
  19. Partial classes: you need to have a very good reason to use a partial class. Tool generated code is one of them.
  20. Avoid multiple returns from a single method unless it is very clear.
  21. Avoid multiple escape routes from a loop, i.e., excessive use of break or continue
  22. Avoid while(true)
  23. Avoid structuring code so that it requires casting; consider generics instead. For example, you have a method that calls another method which returns an instance of an interface. If you need to cast that returned value to a specific class, then you have made a design mistake. Example below
  24. Do not use ApplicationException
  25. Implement the common constructors when making a user-defined excption
  26. Do not use goto

Example of braces on single line statement blocks

✔️ GOOD

if (isFriday) Dance();

// OR

if (isFriday)
{
    Dance();
}  

NEVER THIS

if (isFriday)
    Dance();

Order of items in a class

Note: Codemaid will do this automatically using CTRL + M then space

In a given class sort by:

  • First the type of item
    • Constants
    • Fields
    • Constructors
    • Events
    • Properties
    • Methods
  • Then by accessibility
    • public
    • internal
    • protected Internal
    • protected
    • private
  • Then statics vs instance
    • static
    • instance
  • Then alphabeticly

Bad Casting

This first version forces the caller to cast

public interface ISomeInterface { }

public class SpecificInstance : ISomeInterface
{
    public string Name {get; set;}
}

public interface IReturnAnInterface
{
    ISomeInterface GetInterface();
}

public class ReturnASpecifcInstance : IReturnAnInterface
{
    public ISomeInterface GetInterface()
    {
        return new SpecificInstance() { Name = "MyName" };
    }
}

public void BadCasting(IReturnAnInterface factory)
{
    ISomeInterface instance = factory.GetInterface();
    OtherMethod(((SpecificInstance) instance).Name);
}

✔️ Using generics allows us to avoid the cast

public interface ISomeInterface { }

public class SpecificInstance : ISomeInterface
{
    public string Name {get; set;}
}

public interface IReturnAnInterface<T> where T:ISomeInterface
{
    T GetInterface();
}

public class ReturnASpecifcInstance : IReturnAnInterface<SpecificInstance>
{
    public SpecificInstance GetInterface()
    {
        return new SpecificInstance() { Name = "MyName" };
    }
}

public void NoNeedForCast(IReturnAnInterface<SpecificInstance> factory)
{
    SpecificInstance instance = factory.GetInterface();
    OtherMethod(instance.Name);
}

Example File:

SampleClass.cs

using MySampleCode.SubNamespace;
using System.Linq;
using ZSoft.ThirdPartyNamespace;

namespace MySampleCode
{
    public class SampleClass
    {
        private const int DEFAULT_AGE = 0;

        private static readonly string _someStaticValue;

        protected internal int _size;
        protected double _length;
        private readonly string _vision;
        private string _flavor;

        public SampleClass(
            ITrialUserLicenseCreator trialUserLicenseCreator,
            IUserIdentityProvider userIdentityProvider,
            ILoggedInUserInformationFetcher identityFetcher)
        {
            if (trialUserLicenseCreator == null) throw new ArgumentNullException(nameof(trialUserLicenseCreator));
            // ...
        }

        private SampleClass(string vision, IUserIdentityProvider userIdentityProvider)
        {
            _vision = vision;
        }

        public event EventHandler OnFlavorChanged;

        public string Name { get; set; }

        public void Method()
        {
            // ...
        }

        private int GetIntValue(string value)
        {
            if (string.IsNullOrWhiteSpace(value)) return -1;

            if (value.All(c => char.IsDigit(c))
            {
                return int.Parse(value);
            }
            else 
            {
                return 0;
            }
        }
    }
}

Most of this (all of it) was stolen from Ron’s response to me asking a question on slack.

Took me about a month of raging when I first switched to OSX. These tips might help:

Shortcuts

Keyboard

Keys Effect
⌘ + L Address bar
⌘ + Q Close app
⌘ + Space Spotlight
⌘ + ⌥ + Space Finder
Ctrl + ↑ Mission Control
⌘ + ↑ / ⌘ + ↓ Move up and down the tree. Doing it on a file opens it.
F11 Show desktop
F12 Show dashboard
Ctrl + F3 Focus Dock
Ctrl + F4 Alt-Tab
^ + ⌘ + 3 Save screenshot to file
Ctrl + ^ + ⌘ + 3 Copy screenshot to clipboard
^ + ⌘ + 4 Save screen region to file
Ctrl + ^ + ⌘ + 4 Copy screen region to clipboard
^ + ⌘ + / Show Help Menu
⌘ + ⌥ + → Next tab (chrome)
⌘ + ⌥ + ← Previous tab (chrome)

Magnet

Keys Effect
^⌥← Left
^⌥→ Right
^⌥→ Up
^⌥↓ Down
^⌥U Top Left
^⌥I Top Right
^⌥J Bottom left
^⌥K Bottom Right
^⌥D Left Third
^⌥E Left Two Thirds
^⌥F Center Third
^⌥T Right Two Thirds
^⌥G Right Third
^⌥↵ Right Third
^⌥C Center

Trackpad Gestures

Gesture Effect
Scroll left or right with two fingers Swipe between pages
Swipe left or right with 3 fingers Switch desktop
Swipe left from edge Notificatin Center
Swipe up with three fingers Mission Control
Pinch with all the fingers Launchpad
Spread out thumb and three fingers Show Desktop

Finder keyboard

They actually feel more rational to me than Explorer now tbh.

  • Cmd+up/down to move up and down the tree. Doing it on a file opens it. Vs
  • Explorer, you have to switch to Enter to open a file. Hitting enter on a
  • file (or most labels really) initiates a rename vs F2

In general:

  • Cmd+Space is your friend
  • As Kevin mentioned, Cmd instead of Ctrl. I actually prefer this now since I can use my thumbs for Cmd instead of my pinkies for Ctrl (my thumbs are usually out of play for keyboard shortcuts anyway). Think Cmd+A vs Ctrl+A
  • Cut/Paste flow is different. It’s more like Copy/Move and Move is considered a modification to Paste, so copy as usual (CMD+C), then modify Paste into a Move with Option (Option + CMD +V)
  • Option modifies all sorts of things, and they aren’t well documented. Try option clicking everything I guess. E.g. after right clicking on a folder in Finder to show the context menu, you can hold down Option to show additional command variations
  • You can drag files from anywhere into an Open File dialog and the dialog will jump to that path with that file selected. Versus Windows, last time I used it, doing that will just freak it out.
  • If you hate excessive clicking like me (and it sounds like @brewdente also), turn on triple finger dragging, which lets you just do a 3 finger touch to drag windows around. Otherwise, you have to do a full click, hold it down, and drag. It’s oddly hidden in Accessibility now.
  • You can change touch to be equivalent to click, so it’s more akin to a smart phone (I hate clicking)
  • Turn on the speaker and bluetooth icons. All those status icons are hidden by default. You can turn them all on in System Preferences. This lets you quickly switch inputs and outputs.
  • If you Option click the Notification icon in the top right (looks like a modified hamburger icon), it’ll snooze your notifications. Great for when you’re presenting off your mac and you don’t want random calendar invites appearing
  • There are a lot of 3rd party windows managers if the OS ones aren’t sufficient, like Magnet
  • Install this if you want a soothing screen saver: https://github.com/JohnCoates/Aerial

Windows management

  • Full screen is weird on macOs and defaults to launching an addtl desktop for it. If you’re into multiple desktops, I guess that’s fine, but I never used them under either OS.
  • If you DO like multidesktops, click and drag an app to the top and beyond (like you’re trying to go off screen with it). It’ll prompt you to move the app into a different desktop.
  • Not sure if this was ever added to Windows, but same thing, if you move your mouse to the edge of an app, you get the resize icon. but if you double click instead, it’ll go full screen in that direction only.
  • Hold down the green full screen button on an app to trigger side by side mode. You can also use the drag up technique I mentioned above to trigger the same effect on a different desktop if there’s already a full screen app on it
  • Triple finger swipe down on the touch pad will show all open windows for the current app only
  • Closing all windows is not equivalent to exiting the app. Not sure if MS ever changed that for Windows, but it drove me crazy whenever I accidentally closed my only browser window and it defaulted to exiting out. Cmd+Q to actually exit an app.

Hope that helps.