top of page

COLORCLOCK

What time is it?

Amber o'clock-ish (?)

The mystery of the missing package

A couple weeks ago I was tearing my house apart to find a package from Adafruit that I remember arriving a couple months prior. I'm not one to put something in a random place (except for my phone, an ongoing challenge I'm actively addressing!), so it turned into a whole week of organizing and repeatedly checking all the logical places it could be. I felt like I was going crazy.


I finally decided to find the email delivery confirmation but it was non existent in my inbox. And then I went to the Adafruit website and found a shopping cart containing all the items I was expecting in my package 😑 Looking at my shopping cart of unpurchased items, the real memory of what happened came flooding back... I was shopping for an encoder but couldn't commit and probably went to bed with intentions of finishing my shopping the next day but life got in the way. Studying my shopping cart, I discovered that one of the items I had planned to purchase was no longer in stock 😫


Lessons learned

  1. When having trouble finding a mailed package, first check if the items were ever ordered.

  2. Don't put off ordering a shopping cart full of items in hopes of finding that last perfect addition.


A new Arduino

One of the other items I had ordered that week was a new, smaller Arduino board. I have been using this old board I acquired from my brother years earlier that he was never able to connect to (it turns out he was using a power cable instead of a data cable to program 😅). For the final ColorClock installation, I want to make two identical circuit boards so I have a backup in case there are any problems during the week the project is being displayed.


I ordered an Arduino Nano ESP32 where nearly all of the pins are configurable to have PWM, a way to fake out an analog output with a digital signal. PWM output is what I need to have variable output voltage so I can send different outputs to the RGB LED pins creating different colors.


Nothing good is ever easy

So, I had this new Arduino and I just wanted to do a simple test so that I know I can talk to it. In my last post I shared my frustration with figuring out how to set build variables so I went back to developing on my beloved decade-old MacBook Pro. But after I figured out how to set build variables I migrated back to my new fancy Windows machine and applied the same changes to the boards.txt deep in the file system in the Arudino hardware folder. At that point I continued development on Windows.


Ok, back to the new Arduino board... I installed the drivers to talk to this board but I kept getting errors when trying to program it:

dfu-util: Cannot open DFU device 2341:0070 found on devnum 10 (LIBUSB_ERROR_ACCESS)
dfu-util: No DFU capable USB device available
Failed uploading: uploading error: exit status 74

I discovered that this was a known problem with this board and found in the Arduino forums that there is a post_install.sh script I need to run for the computer to see the Arduino. But this was a Bash script, and I was developing on Windows. I tried running the command in Git Bash, but I needed to use sudo and Git Bash didn't have sudo then I tried to run it in PowerShell just for fun.


A side note

Skipping ahead to the present, as I'm cleaning up this post and adding links, I have discovered that there is indeed a post_install.bat script that I probably could have run on Windows, but we're here now.


A solution to my development woes

The time had come to create a Linux partition. I was experiencing the same level of fear I had about arduino-cli, the command line tool for building and uploading Arduino code. Creating a Linux partition seemed scary because I had never done it before. But dammit I am a software engineer and I can do hard things!


My supportive partner assured me that setting up a Linux partition was not complicated. All I needed to do was download the Linux installer, put it on a USB drive, make it bootable, then boot into that USB drive. deep breath I can do this.


Creating a bootable USB was surprisingly painless. There are tons of instructions on the internet. The basic steps were:


  1. Download the Linux installer image.

  2. Make the USB stick bootable.

  3. Restart the computer and enter the BIOS.

  4. Select the USB from the boot menu.

  5. Follow on-screen instructions.


So I did it! I am actually writing this from my Ubuntu partition right now!


Like any new computer, there's the initial setup process, which, in my case, was missing even basic tools like Vim. But I'm no stranger to starting over.


Back to the new Arduino

The catalyst for the Linux partition was so that I could run a script that would allow my computer to see the Arudino Nano ESP32. I did all the things (installed arduino-cli, ran the post_install.sh script) and it's all working!


My next challenge is to test my new RTC module, test the I/O expander 🥺 (also scary) and start laying out the 'final' V1 version of the circuit board.


In other news... we're famous!

ColorClock is officially listed as 2024 Playa Art!! (go on, click the picture 😀)


Every software hurdle feels like an epic journey. My latest challenge was learning how to set build flags.


Background

I have a class called ColorClock with a member variable, clock_, which is of type DS3231, a real-time clock (RTC) module that keeps time. There's a simple API to interact with this object over I2C. A ColorClock object uses clock_ to get the current time in order to determine which color to display. E.g.

#include <DS3231.h>  

class ColorClock {
  private:
    DS3231 clock_;

  //...
}

RgbColor ColorClock::time_to_color() {
  //...

  float the_hr  = (float) clock_->get_hr();

  //...
}

Right now the only application for a ColorClock object is in the the context of the physical light installation. However, there might be an application in the future where I want to use the `ColorClock` class in a different project with different hardware, or just for a general purpose computer application. Due to the possibility of using this code with a variety of different hardware configurations, I wanted to make the ColorClock class more modular, and not have the code directly tied to the RTC module mentioned above.


So, I decided to make a wrapper class for the clock, which I'm going to call FluxClock*. The intention of this class would be a general clock object that I can use to get or set the time. I would have build environment variables that tell the compiler to include or exclude certain parts of the code. For example, the FluxClock::get_month() function would look like this:

#if ARDUINO_BUILD
#include <DS3231.h>
#else
#include <ctime>
#endif
//_________________________________________________________________
byte FluxClock::get_month()
{
#if ARDUINO_BUILD //_________________________________________________________________
// The century_bit toggles when there is roll-over to a new
// century, e.g. from year 2099 to 2100. The century_bit will
// likely never be relevant for any use case for this code base.
//_________________________________________________________________
  bool century_bit;
  return rtc_.getMonth(century_bit);
#else
  time(&clock_);
  time_ = localtime(&clock_);
  return time_->tm_mon;
#endif
}
//_________________________________________________________________

My challenge was to figure out how to set these build environment variables so that the compiler would only compile what was necessary for the specific build configuration.


The things that didn't work


Define it in a header file

Initially, I included the macro definition, ARDUINO_BUILD in a separate file called macros.h:

#define ARDUINO_BUILD 1

I included macros in ColorClock.hpp:

#include "macros.h"

A more experienced software engineer, or even just someone who's taken a compiler class (it's on my list of things to do) would probably know immediately why this didn't work. But with my limited time, I was less interested in the why-it-doesn't-work part; I was more in the in the how-do-I-get-it-to-work mindset (though feel free to school me on this topic).


Build properties in arduino.json

For reasons mentioned in a previous post, I (was) using the Microsoft Visual Studio Code Arduino plugin to build and upload my code. The internet told me that I could set build environment variables in the arduino.json file but this didn't work either 😕


(I don't actually remember the syntax I used in arduino.json - maybe something with defines (?) - otherwise I would have included it here as something not to do...)


Windows Arduino Command Line

So then I decided to ditch the plugin and go back to command line using arduino-cli (on Windows). I tried using the arduino-cli command in Git Bash, and PowerShell but Windows didn't recognize the command. So I downloaded arduino-cli and stuck the arduino-cli.exe file right in my code directory and Git Bash finally found it when I ran ./arduino-cli. I realize now that I probably just needed to add the location of arduino-cli.exe to my path, but yeah, I was just in a frenzy trying to get something to work. I made a minimal example without any build flags and spent way too much time just figuring out how to set the right serial port so I could upload the code to the board. But I was able to figure that part out.


Now on to the build flags problem... I tried many variations of setting a build flag (FLUX) in the command line argument of arduino-cli compile. But the compiler spit out all sorts of weird errors with every variation. Don't use this command, it doesn't work:

arduino-cli compile --fqbn arduino:samd:mkr1000 --build-properties build.extra_flags=-DFLUX=42

Old tech with a config file

I gave up on Windows and went back to my 10 year old MacBook and started from scratch with my familiar, safe, UNIX command line. I did more internetting (with my friend ChatGPT) and found that I should be able to set build flags in an arduino config file.

build:
  properties:
    FLUX:"42"

I set the config file path in my command line argument...

arduino-cli compile --fqbn arduino:samd:mkr1000 --config-file path/to/arduino_cli.yaml

but nope, this didn't work either. ChatGPT failed me. It then clarified that that the compiler might not actually recognize the flag 😐


And now the thing that worked


Deep in the Arduino installation directory...

Once again, after spending what seemed like ages (but was probably closer to an hour) searching on the internet and more talking to ChatGPT, I learned that I needed to edit the platform.txt file deep inside my install directory:

Users/rebeccarashkin/Library/Arduino15/packages/arduino/hardware/samd/1.8.13/

and set my build flags in build.extra_flags:

build.extra_flags= -DFLUX=42

But this didn't work either! However, I did see a note just above the build.extra_flags line that said "These can be overridden in platform.local.txt" so I figured build.extra_flags might be getting overridden in the build process. I also read somewhere that I can also edit build flags in boards.txt. So I opened boards.txt in the same directory and found the build.extra_flags variable for my board and appended the variable that corresponded with my Arduino board, the MKR 1000

mkr1000.build.extra_flags= -DFLUX=42

Eureka! 🥳


FINALLY the compiler recognized my build flag.


It worked, but come on.

However, digging that deep into an installation directory just to set a build flag seems a little excessive, so I'd like to learn more about the platform.local.txt file. Buuuut.... for now, I really only have one build flag that I care about and I'm ok hacking my way through setting a build flag if it means I can progress in my development.


Ok, now what was I trying to do again? 😅


* Flux was my beloved rabbit companion for over 10 years and died in 2019. His memory lives on in nearly all of my software engineering endeavors.




In the previous construction design we had a simple lean-to structure where the participant would be sitting under the diagonally positioned shade panel. We mocked it up in the garage and noticed that the participant would maybe be a little too cozy with the light display. We decided to create an extension with a roof-top to enable a greater appreciation for the piece.


 


The participant is sitting quite close to the light display in the original structural design.


 

I don't have much experience with structural fabrication, so my construction lead sketched out this design of the rooftop extension.


Rooftop extension enables the participant to sit further from the light.


 

Then I prettied it up and drafted a couple kind-of-but-not-exactly-to-scale isometric and side views.



To provide scale, the human figure in the side view is approximately me-sized (around 5 ft tall). As for the light display, each ring's color corresponds to different time granularities, such as day, hour, and minute. The central light will be user-controllable.


 

Regarding the software, I've been working on developing the time controller. This element enables the artist to designate the current time, which acts as the input for the RGB LED light display, mapping time to color.



There's a lot left to do and we have about five months to complete this thing. But I know we'll make it happen 🤓

bottom of page