Category Archives: How-to

How To Make An Aviation Cocktail

A few weeks ago, my wife and I started cleaning out her mother’s kitchen of the ~40 years of detritus she’s been holding on to. In the fray, I managed to save some really beautiful glassware such as these coupes.

My mother-in-law works for a law firm and one of the attorneys gave her these phenomenal sets of crystalware at Christmas. She didn’t want to part with them out of guilt, but she also *never* used them.

“Take them!” she yelled with her thick Cuban accent. “If you’ll use them, take them!”

Now, I’ve never really been one for fancy glassware (excepting the various branded pint glasses I collected for years), but I’ve always secretly wanted to have a really cool bar setup for entertaining.

So, under the guise of acquiring some really nice crystal wine glasses that Barbie has always wanted to use, I brought home my favorites.

Tonight I’m going to (forgive the expression) break them in.

Now, over the last 18 months, I’ve become a bit of a cocktail aficionado. I mean, I was already into the tiki scene since, like, 2008-ish, but I never really thought about learning to make these drinks myself. All that changed when COVID decided that I couldn’t go out anymore.

At the same time, I rekindled my appreciation for Alton Brown by watching Quarantine Qitchen on YouTube. Brown and his wife Elizabeth live in my hometown and I’ve always considered him kind of a “TV uncle” along with LeVar Burton and Adam Savage.

Seeing Brown’s eclectic collection of glassware inspired me to look around for some interesting pieces on my own, but eBay prices are way too high and thrifting really wasn’t a thing for a while (I still want to pick up a couple of those vintage Delta in-flight service glasses, though!)

So, tonight, after an extremely difficult month, I’m finally going to sit down and enjoy one of my favorite beverages. It’s a classic gin cocktail from the dawn of an era:

The Aviation

First, though, I need to decide on a glass: Do I go with the classic “Marie Antoinette” round coupe or the more stylistic, angled “Martini” coupe?

For tonight, I’m going with Marie just because she’s about a half an ounce larger (also so I can pretend I’m Leonardo DiCaprio in that Great Gatsby GIF)

via GIPHY

Okay, got a clean glass. First thing we’re gonna do is fill it with ice and set aside to chill.

First, let’s talk about hardware. Unlike many modern bartenders who prefer a fancy Boston shaker, I’m very partial to the Parisian shaker.

It’s got a nice period silhouette, but it’s only 2 pieces–unlike the cobbler variety most used by home gamers.

I like it over the Boston because (A) it just looks better, (B) doesn’t require a glass, and (C) seals better.

The Boston is for showing off, and I never strain with it (but many bartenders will tout that benefit anyway)

I can’t recommend a graduated jigger enough! Measurements get much faster and easier than eyeballing. Japanese or hourglass, it doesn’t matter (I just happen to like the look of the Japanese style)

Last thing is a good spring strainer. A Boston shaker can be used as a makeshift strainer, but if I’m going to strain a drink, I’m going to strain it!

This guy will get all those tiny ice flakes out so they don’t mess with the experience of a neat drink.

I’m going with the classic Savoy recipe here, but I’ve been playing around with the recipe some. Biggest change is that I’m going to be using violet liqueur instead of creme de Violette–because that’s what they had at Bevmo!

It’s really such a small amount only for coloring that it doesn’t appreciably affect the flavor. Despite what some purists will tell you!

Okay, let’s start with the good stuff! I am a fan of Sapphire going way back to my early 20s, but I haven’t bought it in over a decade. I switched to beer for a long time, and I picked up Beefeater for my tiki stuff since it was going to be so heavily mixed.

Not that there’s anything wrong with Beefeater! But if I’m going to be doing mostly gin, I want to taste my favorite.

That’s 1.5oz into the tin!

Maraschino liqueur fell by the wayside for a long time, but it is absolutely delicious and adds a nice, round cherry flavor to boozy cocktails like the Aviation, Manhattan, and Hemingway. We’re going to use 0.75oz for our concoction.

I don’t have any fresh lemons, but this will do for tonight. I need to get a couple of citrus trees for the apartment…. 😉 Throw in 0.5oz of lemon.

This is *not* the good stuff, but it’s what they had. Again, it’s really mostly for color and just a slight perfume of violet. Use 0.25oz at most.

Throw the ice from your glass in the tin and shake! (Yes, shake!) You don’t have to get violent here, just enough to mix and get the tin cold.

via GIPHY

Strain it into that chilled glass. Don’t that look something!

Now for the garnish! Most plebes use some of those neon red cherries that come in Dole fruit cocktail, but I’m gonna fancy it up a little bit for my new glass.

My step-sister and I discovered these at Trader Sam’s when she was out here for a conference a couple years ago. They’re stupid expensive, but so goddamned delicious!

And there we have it! Of course, keeping with the aviation theme, I had to use one of my Southwest Airlines swizzle sticks!

Delicious! And, as promised, my best Gatsby selfie 🍸

Now, there is very likely a contingent of you who reel at the thought of shaking an aviation (“You’ll bruise the gin!”). I get it, especially with a top shelf gin like Sapphire, you don’t want to lose those nice top notes from the juniper and pine.

However, we have to take into consideration the complexity of the drink. By adding Maraschino, lemon, and Violette, we’re replacing much of the top notes with these new flavors. And when I shake a drink like this, I go just long enough to get the tin cold. On top of that, the ice dilutes the drink a little bit to give it a smoother texture. The shake also creates a tiny bit of foam, reminiscent of cirrus clouds, which help give the drink it’s distinct appearance (the drink is supposed to evoke the idea of an open sky, hence the name).

On the other hand, if this were a martini, you’d better believe I’d be stirring!

At the end of the day, it’s your drink! Make what you want how you want, and don’t let anyone shame you for being unorthodox. Just don’t be that asshole who drives drunk or ends the night praying to the porcelain gods!

Have fun, y’all. Hug your loved ones if you can.

Installing Mojave on a 12-year-old iMac

Let’s take a trip, shall we? I used to use this 2010 iMac at my office before it became hopelessly outdated. It’s spent close to the last half decade in storage at the shop (just off the left side of the screen in videos, actually). I’m gonna try to repurpose it

I forgot the account password, so I’m going to reinstall the OS

Silly me! Despite the wallpaper, it already has Mavericks on it

I wiped the hard drive to perform a fresh install of Mavericks. For some reason, I *really* hate entering my Apple ID. Probably because there’s always about 8 hoops I have to jump through (yay multi-layered security?) because I refuse to carry the Fruit Fone.

I actually have 2 of these lumbering beasts. Maybe I’ll put some flavor of Linux on the other for funsies.

Actually, thinking about it. It’ll probably be more useful running a newer version of Ubuntu than trying to force a newer version of OS X.

Still, I’M GONNA HAVE FUN TRYING!!!

Well, THAT took forever….

Well, there’s no big 🚫 over the icon. Let’s see if we can just run the app

Poop. That would’ve been TOO easy.

Gonna try DOSDude’s patcher and see what happens. dosdude1.com

Basically, this application patches the installers for newer versions of OS X so they’ll work on older Mac hardware. I’ll have to do this for every incremental update through Mojave.

This is promising….

Thinking aloud: If I do end up putting Linux on one of these, will it still have the chime? I don’t think it will, but I don’t recall ever trying to find out.

I came to really enjoy the chime. I was *mad* when Apple silenced it with the High Sierra “upgrade”.

Pretty sure the chime, then, is part of the OS and not, say, a bootloader? That would take some research.

MUAHAHAHAHA!!!

Seriously, though: I relish when something that *shouldn’t* work does. I feel like Alan Cumming in GoldenEye (even if I am just using a publicly available tool written by someone else)

Another half an hour waiting for the OS to install. I’m going to put this aside for the night and get some sleep.

Got up this morning and went to check on the Sierra install, but instead I got a big 🚫. Something obviously went wrong, now to see if I can recover.

“Success! Success! They’ve done it! They’ve done it!”

The trick is that you have to use a very specific version of the installer app with the patch–otherwise it will not install correctly. I managed to find a copy of 12.6.06 on archive.org and it worked a charm!

Let’s see how far we can ride this train. Hold on to your butts!

Aww yiss

LET IT RIDE!!!

It is done! I present to you, in sheer defiance of Cupertino, a 12-year-old iMac running the last version of OSX to support 32-bit apps! As much as I’d like to try, I’m going to hold off on upgrading to Catalina–this will serve my needs just fine.

How To Install Pi-Hole on FreeNAS

I’ve been playing around a lot with my FreeNAS installation since assembling it last year as my “Pandemic Project” (which, of course, would become the first of many), and I’m constantly looking for new things to implement. Advertising has been a thorn in my side since the early days of the internet, so it seemed only logical that I should see what all the fuss with Pi-Hole was about!

Pi-Hole is most readily installed on a Raspberry Pi, but I’m trying to consolidate as much of my infrastructure as possible, so I thought I might have a go getting it working on the server. Unfortunately, FreeNAS is based on BSD while Pi-Hole is written for Linux (so there’s no plugin available), so we’ll have to install it on a virtual machine.

Installing Ubuntu Server on a Virtual Machine

The first thing we’ll need, of course, is the installation media. There’s a flavor of Pi-Hole written specifically for Ubuntu, so that seems to be the logical choice! My recommendation is to install the most compact version available, and the netboot installer image allows you to pick Ubuntu Server with minimal options. It’s a little difficult to find the correct download, so just grab the URL below:

http://archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/current/images/netboot/mini.iso

Of course, if Bionic Beaver is outdated, just change the /bionic directory to the current version!

Back in FreeNAS, go to the Virtual Machines menu and add a new Linux VM. Give it a name that you’ll remember (“pihole” is a solid choice) and set the virtual CPU count to 1 and the memory size to 512MiB. On the Disks page, create a new AHCI disk and set its Zvol location to /data/pihole and size to 4GiB. When you get to the options for installation media, select “Upload an installer image file” and choose the mini.iso file you downloaded earlier. Once all your settings are configured, you can boot the virtual machine and install Ubuntu. The VNC option opens a virtual terminal that will allow you to connect to and interact with the virtual machine through the installation process.

If you are prompted for DNS servers, use Google’s (8.8.8.8 and 8.8.4.4) as a default for now.

When the install completes, Ubuntu will prompt you to remove installation media and reboot. Once you are disconnected from the VNC, stop the virtual machine and remove the installation media by deleting the CDROM from the “Devices” list under the virtual machine options.

Setting up Pi-Hole

Restart the virtual machine and connect to the VNC. Log into Ubuntu and invoke the following commands:

sudo apt update
sudo apt upgrade
sudo apt install net-tools
sudo apt install wget

The first thing we need to do is set up a static IP address for the virtual machine. Use ifconfig to find the local IP address.

In this example, the device is called ‘enp0s4’.

We will now need to change the settings for this device by editing the netplan config. Invoke the following command:
sudo nano /etc/netplan/01-netcfg.yaml

You will need to change edit the file so that it look like the image below. Pay special attention to the number of spaces for each indentation.

Once this is complete, reboot the VM.

After rebooting and logging back into Ubuntu, install Pi-Hole using the automatic installation script, just like you normally would.

wget -O basic-install.sh https://install.pi-hole.net

sudo bash basic-install.sh

Before you log into

Once the script finishes, you can access the web UI by navigating to [PIHOLEIPADDRESS]/admin. Make sure to change your password!

The last thing you’ll need to do is set up your router’s DHCP settings, but that’s best explained by Pi-Hole’s own documentation.

Using Pi-Hole For Whole-Network Ad Blocking

Internet advertising was once a fairly benign minor annoyance that spiraled into the oft-lampooned dark world of pop-ups on top of pop-ups. In these early years, simple ad-blocking plugins for popular browsers like Netscape Navigator (and its successor, Mozilla Firefox) were enough to keep these nuisances at bay, but as advertising technology got more sophisticated, Web 2.0 became more commercialized, and surveillance capitalism became the business model du jour, ad-blockers have moved from convenience to absolute necessity while simultaneously become more difficult to implement at the browser level.

Most commercial websites now can detect ad-blocker software and refuse to serve content in response. In these cases, it becomes necessary to allow some level of ad servicing–usually through whitelisting specific sites–but this also comes at the extended (and immeasurable) cost of privacy. Advertising networks track users’ movements across the internet and serve consistent ads based on that user’s specific browsing history. In this Brave New World, a user’s very identity is a commodity that must be exchanged in order to participate in society. One must sell their soul in an asymmetrical exchange to merely experience the world outside while the buyer resells the soul indefinitely and reaps exponential profits.

Pi-Hole is an application that adjusts the balance of power back into the hands of the user by allowing ads to be served, but intercepting and dumping them into a “black hole” before being displayed. Additionally, Pi-Hole blocks trackers from “phoning home” by directing their calls into the same virtual black hole, thus allowing the user to retain control over their identity. The result is a cleaner, safer, and more pleasant user experience with faster page load times and less noise in the browsing experience. Granted, Pi-Hole does have a few flaws that are more difficult to work around (such as Google’s first-party tracking), but by-and-large, the application is well-worth the few minutes that it takes to set up.

In my current network arrangement, I have Pi-Hole installed on a Raspberry Pi Zero W plugged into a 5V wall wart and connected to the WiFi. It’s not the fastest arrangement, of course, but it has a very low power consumption and serves my needs at the moment. I have also tried using Pi-Hole installed on an Ubuntu virtual machine in my FreeNAS server, but I noticed that it resulted in a noticeable increase in system resources (and noise, considering the case sits behind my sofa) so I migrated to the Pi. If you have the hardware to spare, I would probably recommend a Pi3B+ or better as the right nexus of speed and power consumption.

Installation on the Pi is fairly straightforward, following the directions of the Pi-Hole website. The most difficult part seems to be arranging the DNS settings on your router (which isn’t altogether difficult, but it doesn’t enjoy the virtue of an automatic installation script). I will put together a setup guide for the FreeNAS instance in a future number, for those who may be inclined (or whenever I upgrade my server and stuff it in an air-conditioned closet).

Pi-Hole is not a silver bullet to stop advertising and privacy-invading browser trackers wholesale, but I do recommend it as another tool in the ever-growing arsenal that users can employ to reclaim some of their own power on the internet. I’m still playing around with the idea of obfuscation, and seeing if it is even worth considering (it probably isn’t, but it may just be for fun), and I have been implementing other changes that have made my life–both online and especially off–better and less stressful than it used to be.

How To Automatically Select Random Google Wear Android Watch Faces

Say you’re an aficionado of novelty like I am, but you also don’t like being overwhelmed by the paradox of choice when it comes to the myriad Google Wear watch faces. I have a huge array of Android watch faces installed, and I would like to have a way to randomly select a new watch face every day. To automatically select a random Google Wear Android watch face, you just need to have the Tasker app installed on your primary Android device with the AutoInput plugin also installed.

Once those prerequisites are met, you can create a task in Tasker called “Switch Watchface” and populate it with the following code:

A1: Array Push [ Variable Array:%watchfaces Position:9999 Value:/*ENTER THE NAME OF THE WATCH FACE HERE*/ Fill Spaces:Off ]
A2: Array Push [ Variable Array:%watchfaces Position:9999 Value:/*USE AS MANY 'ARRAY PUSH' LINES AS YOU HAVE WATCH FACES YOU WANT TO SELECT FROM*/ Fill Spaces:Off ]
A3: Variable Set [ Name:%count To:%watchfaces(#) Recurse Variables:Off Do Maths:Off Append:Off Max Rounding Digits:0 ]
A4: Variable Randomize [ Name:%random Min:1 Max:%count ]
A5: Variable Set [ Name:%watchface To:%watchfaces(%random) Recurse Variables:Off Do Maths:Off Append:Off Max Rounding Digits:0 ]
A6: Popup [ Title: Text:Switching watch face to %watchface Background Image: Layout:Popup Timeout (Seconds):1 Show Over Keyguard:On ]
A7: Launch App [ Package/App Name:Android Wear Data: Exclude From Recent Apps:Off Always Start New Copy:On ]
A8: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
A9: AutoInput Action [ Configuration:Type: Text
Value: More
Action : Click Timeout (Seconds):23 ]
A10: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
<check if on screen>
A11: AutoInput UI Query [ Configuration:Variables: faces() Timeout (Seconds):20 ]
A12: If [ %faces(#?%watchface) eq 0 ]
A13: Flash [ Text:Didn't find %watchface. Scrolling... Long:Off ]
A14: AutoInput Action [ Configuration:Type: Id
Value: com.google.android.wearable.app:id/watch_face_inner_frame
Action : Scroll Forward Timeout (Seconds):20 ]
A15: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
A16: Goto [ Type:Action Label Number:1 Label:check if on screen ]
A17: Else
A18: Flash [ Text:Found %watchface. Switching to it! Long:Off ]
A19: End If
A20: AutoInput Action [ Configuration:Type: Text
Value: %watchface
Action : Click Timeout (Seconds):20 ]
A21: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
A22: AutoInput Action [ Configuration:Type: Text
Value: Set on watch
Action : Click
Is Tasker Action: false
Check Screen State: false Timeout (Seconds):1 Continue Task After Error:On ]
A23: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
A24: Go Home [ Page:0 ]

What this task does is it creates an array populated by the names of each watch face to be selected from. Then it creates a variable %count whose value is the number of items in the array. Then it creates a %random variable with a value of a randomized number between 1 and the value of %count.  With as the random number selected, it assigns the %watchface variable the name of whichever watch face is located at that position in the array.

With a %watchface defined, Tasker launches the Android Wear app, looks for the word “More” on the screen, taps it to bring up the list of watch faces, looks for the name of the watch face (it’s important that the %watchfaces array is populated by exact matches, otherwise Tasker will not find them!), taps the menu icon for the watch face, then taps “Set on watch”, setting the watch face.

If Tasker doesn’t find the name of the watch face, it will automatically scroll, looking for the name of the face.

Once the watch face has been set, Tasker will exit the app back to the home screen. The whole process takes about 5 seconds or so, depending on how many times Tasker has to scroll.

For your convenience, I have saved this task as an XML file that can be directly imported into Tasker. You can download that file here.

How To Solve Rubik’s Cube Every Time

As a child of the 1980s, I’ve been fascinated by the apparent complexity of Rubik’s Cube–the world-famous puzzle toy designed by Hungarian architect Emö Rubik–but I could never solve one past peeling the stickers and placing them in the correct position (a trick my uncle taught me that could be used to “mess with the Cube nerds”). I’ve had a newer model sitting around for a few years, and as one of my “COVID Side Projects”, I finally learned the proper way to solve the Cube.

Get the Original Rubik’s Cube on Amazon.com

The Algorithms:

Building the yellow cross:

If you have no yellow edge pieces on the top face, then F U R U’ R’ F’

If you have a line of yellow pieces through the center, then reorient the entire cube so that the line is vertical to your perspective and F U R U’ R’ F’

If you have two yellow edge pieces making an “L” shape, then turn the top layer until the edge pieces are in the 12:00 and 9:00 positions and F U R U’ R’ F’

Solving the yellow face:

If there are 0 or 2 yellow corners showing, then R U R’ U R U2 R’

If there is 1 yellow corner showing (“the goldfish”), then turn the top layer until the yellow corner piece is in the lower left of the face (the “goldfish” will be diving to the left) and R U R’ U R U2 R’

Set up the top layer:

If there are no matching corner pieces on any faces of the top layer, then L’ U R U’ L U R’ R U R’ U R U2 R’

If there is a set of matching corner pieces on a face, then reorient the cube so that face is on the left and L’ U R U’ L U R’ R U R’ U R U2 R’

Continue until there are matching corner pieces on all 4 faces

Solve the top layer:

F2 U’ R’ L F2 L’ R U’ F2

Continue until the top layer is solved, then rotate the top layer to solve faces as necessary.

How To Set Up A TFT Screen On Arduino With The RA8875

In a previous video, we looked at how to attach a TFT LCD screen to a Raspberry Pi to build a small-form-factor project. But what if your project doesn’t need quite as much horsepower? What if you just need to display shapes and colors on a screen with no operating system and nearly instant boot times? This is where a TFT LCD screen on Arduino comes in handy. In this video, we’ll look at how to set up a TFT LCD screen on Arduino with the RA8875 breakout board from Adafruit then walk through how to display various shapes and colors in the sketch.

PARTS/TOOLS:

(Most of these can be found in the Arduino Starter Kit available here)

Arduino UNO

Solderless breadboard

Jumper (Dupont) Wire

TFT LCD Display

Adafruit RA8875 Breakout Board

RESOURCES:

RA8875 Datasheet

Adafruit RA8875 Arduino Library

THE CIRCUIT:

It’s a fairly simple wiring job here using the hardware SPI interface on the Arduino. CLK, MISO, and MOSI connect to 13, 12, 11 respectively. CS, RST, and INT are defaulted to 10, 9, and 3, but can be reassigned in the sketch. Of course, the display is not illustrated, but it is connected to the 40-pin ribbon connector on the left.

THE SKETCH:

/******************************************************************
 This is an example for the Adafruit RA8875 Driver board for TFT displays
 ---------------> http://www.adafruit.com/products/1590
 The RA8875 is a TFT driver for up to 800x480 dotclock'd displays
 It is tested to work with displays in the Adafruit shop. Other displays
 may need timing adjustments and are not guanteed to work.

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source hardware
 by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries.
 BSD license, check license.txt for more information.
 All text above must be included in any redistribution.
 ******************************************************************/

#include 
#include "Adafruit_GFX.h"
#include "Adafruit_RA8875.h"


// Library only supports hardware SPI at this time
// Connect SCLK to UNO Digital #13 (Hardware SPI clock)
// Connect MISO to UNO Digital #12 (Hardware SPI MISO)
// Connect MOSI to UNO Digital #11 (Hardware SPI MOSI)
#define RA8875_INT 3
#define RA8875_CS 10
#define RA8875_RESET 9

Adafruit_RA8875 tft = Adafruit_RA8875(RA8875_CS, RA8875_RESET);
uint16_t tx, ty;

void setup()
{
  Serial.begin(9600);
  Serial.println("RA8875 start");

  /* Initialize the display using 'RA8875_480x80', 'RA8875_480x128', 'RA8875_480x272' or 'RA8875_800x480' */
  if (!tft.begin(RA8875_480x272)) {
    Serial.println("RA8875 Not Found!");
    while (1);
  }

  Serial.println("Found RA8875");

  tft.displayOn(true);
  tft.GPIOX(true);      // Enable TFT - display enable tied to GPIOX
  tft.PWM1config(true, RA8875_PWM_CLK_DIV1024); // PWM output for backlight
  tft.PWM1out(255);

  // With hardware accelleration this is instant
  tft.fillScreen(RA8875_WHITE);

  // Play with PWM
  for (uint8_t i=255; i!=0; i-=5 )
  {
    tft.PWM1out(i);
    delay(10);
  }
  for (uint8_t i=0; i!=255; i+=5 )
  {
    tft.PWM1out(i);
    delay(10);
  }
  tft.PWM1out(255);

  tft.fillScreen(RA8875_RED);
  delay(500);
  tft.fillScreen(RA8875_YELLOW);
  delay(500);
  tft.fillScreen(RA8875_GREEN);
  delay(500);
  tft.fillScreen(RA8875_CYAN);
  delay(500);
  tft.fillScreen(RA8875_MAGENTA);
  delay(500);
  tft.fillScreen(RA8875_BLACK);

  // Try some GFX acceleration!
  tft.drawCircle(100, 100, 50, RA8875_BLACK);
  tft.fillCircle(100, 100, 49, RA8875_GREEN);

  tft.fillRect(11, 11, 398, 198, RA8875_BLUE);
  tft.drawRect(10, 10, 400, 200, RA8875_GREEN);
  tft.fillRoundRect(200, 10, 200, 100, 10, RA8875_RED);
  tft.drawPixel(10,10,RA8875_BLACK);
  tft.drawPixel(11,11,RA8875_BLACK);
  tft.drawLine(10, 10, 200, 100, RA8875_RED);
  tft.drawTriangle(200, 15, 250, 100, 150, 125, RA8875_BLACK);
  tft.fillTriangle(200, 16, 249, 99, 151, 124, RA8875_YELLOW);
  tft.drawEllipse(300, 100, 100, 40, RA8875_BLACK);
  tft.fillEllipse(300, 100, 98, 38, RA8875_GREEN);
  // Argument 5 (curvePart) is a 2-bit value to control each corner (select 0, 1, 2, or 3)
  tft.drawCurve(50, 100, 80, 40, 2, RA8875_BLACK);
  tft.fillCurve(50, 100, 78, 38, 2, RA8875_WHITE);

  pinMode(RA8875_INT, INPUT);
  digitalWrite(RA8875_INT, HIGH);

  tft.touchEnable(true);

  Serial.print("Status: "); Serial.println(tft.readStatus(), HEX);
  Serial.println("Waiting for touch events ...");
}

void loop()
{
  float xScale = 1024.0F/tft.width();
  float yScale = 1024.0F/tft.height();

  /* Wait around for touch events */
  if (! digitalRead(RA8875_INT))
  {
    if (tft.touched())
    {
      Serial.print("Touch: ");
      tft.touchRead(&tx, &ty);
      Serial.print(tx); Serial.print(", "); Serial.println(ty);
      /* Draw a circle */
      tft.fillCircle((uint16_t)(tx/xScale), (uint16_t)(ty/yScale), 4, RA8875_WHITE);
    }
  }
}

Driving LED Displays With Arduino And MAX7219

The Arduino platform is great for making LEDs blink and driving small displays, but what happens when you need to display more complex information? For Project ColorTyme, I need to drive 6x 14-segment “starburst” style alphanumeric LED displays, but pins are at a premium. To solve the problem, we’ll incorporate the MAX7219 LED display driver; however, it’s an imperfect solution: The displays I’m using are common-anode while the MAX7219 is a common-cathode driver. In this video, we’ll walk through wiring a 14-segment display to the Arduino, then wiring the MAX7219 to drive in common-anode mode while adjusting the code so everything comes out correctly.

PARTS/TOOLS:

(Most of these can be found in the Arduino Starter Kit available here)

Arduino UNO

Solderless breadboard

Jumper (Dupont) Wire

MAX7219 LED Driver

14 Segment LED Display

RESOURCES:

MAX7219 Datasheet

LedControl Arduino Library (patched for common-anode displays)

THE CIRCUIT:

The main thing to remember when wiring in this inverse method is that the segment pins correspond to individual digits while the digit pins correspond to individual segments. This illustration is also limited to a single 14-segment digit, but the pinout for a dual display is what is wired.

THE SKETCH:

//Project ColorTyme
//MAX7219x14-segment Display Proof of Concept
//CC-BY-SA Matthew Eargle
//element14 Presents http://element14.com/presents
//AirborneSurfer Productions http://airbornesurfer.com

#include "LedControl.h"
/*
pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
We have only a single MAX72XX.
*/
LedControl lc=LedControl(12,11,10,1);

unsigned long delaytime=100;
byte numbers[16] = {
B11111100, B01100000, B11011010, B11110010,
B01100110, B10110110, B10111110, B11100000,
B11111110, B11110110, B11101110, B11110011,
B10011100, B11110001, B10011110, B10001110
};
int ones = 0;
int twos = 0;

void setup() {
/*
MAX72XX wakeup call
/
lc.shutdown(0,false);
/
set the brightness /
lc.setIntensity(0,1);
/
clear the display */
lc.clearDisplay(0);
int counter = 0;
}

void loop() {
lc.setColumn(0,2,numbers[twos]);
while(ones <= 15) {
lc.setColumn(0,1,numbers[ones]);
delay(1000);
ones++;
};
ones = 0;
twos++;
}

How To Build A Battery Backup Real-Time Clock

Previously, we looked at how to build a simple DIY Arduino clock. Unfortunately, if power to the clock is disconnected, the whole thing has to be reset. To solve that problem, we’re going to add an Arduino battery backup real time clock module based on the DS1307 RTC package. Instead of purchasing a pre-made part, we’ll walk through how to build a DIY Arduino RTC module from scratch and add it to our clock project.

PARTS/TOOLS:

(Most of these can be found in the Arduino Starter Kit available here)

Arduino UNO

1602 LCD

Solderless breadboard

Assorted resistors (220 and 10K, specifically)

Jumper (Dupont) Wire

10K Potentiometer

Tactile switches

DS1307 Real Time Clock

32.768kHz Crystal Oscillator

Coin Cell Holder

CR2032 Coin Cell Battery

RESOURCES:

DS1307 Datasheet

RealTimeClockDS1307 Arduino Library

THE CIRCUIT:

Assemble the LCD circuit as described in previous projects. Connect the DS1307 pins as indicated in the following illustration:

THE SKETCH:

#include
#include

//RealTimeClock RTC;//=new RealTimeClock();

#define Display_Clock_Every_N_Seconds 10 // n.secs to show date/time
#define Display_ShortHelp_Every_N_Seconds 60 // n.secs to show hint for help
//#define TEST_Squarewave
//#define TEST_StopStart
//#define TEST_1224Switch

int count=0;
char formatted[] = "00-00-00 00:00:00x";

void setup() {
// Wire.begin();
Serial.begin(9600);
pinMode(A3, OUTPUT); //*** pin 16 (Analog pin 2) as OUTPUT ***
digitalWrite(A3, HIGH); //*** pin 16 (Analog pin 2) set to LOW ***
pinMode(A2, OUTPUT); //*** pin 17 (Analog pin 3) as OUTPUT ***
digitalWrite(A2, LOW); //*** pin 17 (Analog pin 3) set to HIGH ***
//*** Analog Pin settings to power RTC module ***
}

void loop() {
if(Serial.available())
{
processCommand();
}

RTC.readClock();
count++;
if(count % Display_Clock_Every_N_Seconds == 0){
Serial.print(count);
Serial.print(": ");
RTC.getFormatted(formatted);
Serial.print(formatted);
Serial.println();
}

if(count % Display_ShortHelp_Every_N_Seconds == 0) {
Serial.println("Send ? for a list of commands.");
}
#ifdef TEST_Squarewave
if(count%10 == 0)
{
switch(count/10 % 6)
{
case 0:
Serial.print("Squarewave disabled (low impedance): ");
RTC.sqwDisable(0);
Serial.println((int) RTC.readData(7));
break;
case 1:
Serial.print("Squarewave disabled (high impedance): ");
RTC.sqwDisable(1);
Serial.println((int) RTC.readData(7));
break;
case 2:
Serial.println("Squarewave enabled at 1 Hz");
RTC.sqwEnable(RTC.SQW_1Hz);
break;
case 3:
Serial.println("Squarewave enabled at 4.096 kHz");
RTC.sqwEnable(RTC.SQW_4kHz);
break;
case 4:
Serial.println("Squarewave enabled at 8.192 kHz");
RTC.sqwEnable(RTC.SQW_8kHz);
break;
case 5:
Serial.println("Squarewave enabled at 32.768 kHz");
RTC.sqwEnable(RTC.SQW_32kHz);
break;
default:
Serial.println("Squarewave test not defined");
}//switch
}
#endif

#ifdef TEST_StopStart
if(count%10 == 0)
{
if(!RTC.isStopped())
{
if(RTC.getSeconds() < 45)
{
Serial.println("Stopping clock for 10 seconds");
RTC.stop();
}//if we have enough time
} else {
RTC.setSeconds(RTC.getSeconds()+11);
RTC.start();
Serial.println("Adding 11 seconds and restarting clock");
}
}//if on a multiple of 10 counts
#endif

#ifdef TEST_1224Switch
if(count%10 == 0)
{
if(count %20 == 0)
{
Serial.println("switching to 12-hour time");
RTC.switchTo12h();
RTC.setClock();
}
else
{
Serial.println("switching to 24-hour time");
RTC.switchTo24h();
RTC.setClock();
}
}
#endif
}

void processCommand() {
if(!Serial.available()) { return; }
char command = Serial.read();
int in,in2;
switch(command)
{
case 'H':
case 'h':
in=SerialReadPosInt();
RTC.setHours(in);
RTC.setClock();
Serial.print("Setting hours to ");
Serial.println(in);
break;
case 'I':
case 'i':
in=SerialReadPosInt();
RTC.setMinutes(in);
RTC.setClock();
Serial.print("Setting minutes to ");
Serial.println(in);
break;
case 'S':
case 's':
in=SerialReadPosInt();
RTC.setSeconds(in);
RTC.setClock();
Serial.print("Setting seconds to ");
Serial.println(in);
break;
case 'Y':
case 'y':
in=SerialReadPosInt();
RTC.setYear(in);
RTC.setClock();
Serial.print("Setting year to ");
Serial.println(in);
break;
case 'M':
case 'm':
in=SerialReadPosInt();
RTC.setMonth(in);
RTC.setClock();
Serial.print("Setting month to ");
Serial.println(in);
break;
case 'D':
case 'd':
in=SerialReadPosInt();
RTC.setDate(in);
RTC.setClock();
Serial.print("Setting date to ");
Serial.println(in);
break;
case 'W':
Serial.print("Day of week is ");
Serial.println((int) RTC.getDayOfWeek());
break;
case 'w':
in=SerialReadPosInt();
RTC.setDayOfWeek(in);
RTC.setClock();
Serial.print("Setting day of week to ");
Serial.println(in);
break;

case 't':
case 'T':
if(RTC.is12hour()) {
RTC.switchTo24h();
Serial.println("Switching to 24-hour clock.");
} else {
RTC.switchTo12h();
Serial.println("Switching to 12-hour clock.");
}
RTC.setClock();
break;

case 'A':
case 'a':
if(RTC.is12hour()) {
RTC.setAM();
RTC.setClock();
Serial.println("Set AM.");
} else {
Serial.println("(Set hours only in 24-hour mode.)");
}
break;

case 'P':
case 'p':
if(RTC.is12hour()) {
RTC.setPM();
RTC.setClock();
Serial.println("Set PM.");
} else {
Serial.println("(Set hours only in 24-hour mode.)");
}
break;

case 'q':
RTC.sqwEnable(RTC.SQW_1Hz);
Serial.println("Square wave output set to 1Hz");
break;
case 'Q':
RTC.sqwDisable(0);
Serial.println("Square wave output disabled (low)");
break;

case 'z':
RTC.start();
Serial.println("Clock oscillator started.");
break;
case 'Z':
RTC.stop();
Serial.println("Clock oscillator stopped.");
break;

case '>':
in=SerialReadPosInt();
in2=SerialReadPosInt();
RTC.writeData(in, in2);
Serial.print("Write to register ");
Serial.print(in);
Serial.print(" the value ");
Serial.println(in2);
break;
case '<':
in=SerialReadPosInt();
in2=RTC.readData(in);
Serial.print("Read from register ");
Serial.print(in);
Serial.print(" the value ");
Serial.println(in2);
break;

default:
Serial.println("Unknown command. Try these:");
Serial.println(" h## - set Hours [range 1..12 or 0..24]");
Serial.println(" i## - set mInutes [range 0..59]");
Serial.println(" s## - set Seconds [range 0..59]");
Serial.println(" d## - set Date [range 1..31]");
Serial.println(" m## - set Month [range 1..12]");
Serial.println(" y## - set Year [range 0..99]");
Serial.println(" w## - set arbitrary day of Week [range 1..7]");
Serial.println(" t - toggle 24-hour mode");
Serial.println(" a - set AM p - set PM");
Serial.println();
Serial.println(" z - start clock Z - stop clock");
Serial.println(" q - SQW/OUT = 1Hz Q - stop SQW/OUT");
Serial.println();
Serial.println(" >##,### - write to register ## the value ###");
Serial.println(" <## - read the value in register ##");

}//switch on command

}

//read in numeric characters until something else
//or no more data is available on serial.
int SerialReadPosInt() {
int i = 0;
boolean done=false;
while(Serial.available() && !done)
{
char c = Serial.read();
if (c >= '0' && c <='9')
{
i = i * 10 + (c-'0');
}
else
{
done = true;
}
}
return i;
}

How To Build An Arduino Clock

Clocks are a rite of passage for hardware hackers, and with this video you can start working on your DIY Clock merit badge using the Arduino platform to build a basic Arduino clock. This project builds on the Arduino Fortune Teller project from the “Arduino For Kooks” basic series and teaches programming concepts like timing and actively updating a display, so you can use it as a springboard for many more complicated projects!

PARTS/TOOLS:

(Most of these can be found in the Arduino Starter Kit available here)

Arduino UNO

1602 LCD

Solderless breadboard

Assorted resistors (220 and 10K, specifically)

Jumper (Dupont) Wire

10K Potentiometer

Tactile switches

The Circuit:

Connect the LCD module as described in the Liquid Crystal Ball project. You can use the breadboard to create buses for +5V and GND. Connect one side of one tactile switch to D8 and the other to a 10K resistor to ground. Connect one side of the other tactile switch to D9 and the other side to a 10K resistor to ground.

The Sketch:

//Projet ColorTyme
//Phase 1: Simple LCD Clock
//CC-BY-SA Matthew Eargle
//AirborneSurfer.com
//element14 Presents

#include "LiquidCrystal.h"

// Define LCD pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// initial Time display is 00:00:00 (24hr clock)
int h=00;
int m=00;
int s=00;

// Time Set Buttons
int button1;
int button2;
int hs=8;// pin 8 for Hours Setting
int ms=9;// pin 9 for Minutes Setting

// Digital LCD Constrast setting
int cs=6;// pin 5 for contrast PWM
static int contrast=100;// default contrast

//Define current time as zero
static uint32_t last_time, now = 0;

void setup()
{
lcd.begin(16,2);
pinMode(hs,INPUT_PULLUP);
pinMode(ms,INPUT_PULLUP);

now=millis(); // read RTC initial value
analogWrite(cs,contrast);
}

void loop()
{
// Update LCD Display
// Print TIME in Hour, Min, Sec
lcd.setCursor(0,0);
lcd.print("Time ");
if(h<10)lcd.print("0");// always 2 digits
lcd.print(h);
lcd.print(":");
if(m<10)lcd.print("0");
lcd.print(m);
lcd.print(":");
if(s<10)lcd.print("0");
lcd.print(s);


lcd.setCursor(0,1);// for Line 2
lcd.print("SURF STD TIME");

while ((now-last_time) < 1000 ) // wait1000ms
{
now=millis();
}

last_time=now; // prepare for next loop
s=s+1; //increment sec. counting


/-------Time setting-------/
button1=digitalRead(hs);
if(button1==0)
{
s=0;
h=h+1;
}

button2=digitalRead(ms);
if(button2==0){
s=0;
m=m+1;
}

analogWrite(cs,contrast); // update contrast

/* ---- manage seconds, minutes, hours am/pm overflow ----*/
if(s==60){
s=0;
m=m+1;
}
if(m==60)
{
m=0;
h=h+1;
}
if (h==25)
{
h=0;
}

}