top of page

COLORCLOCK

What time is it?

Amber o'clock-ish (?)

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 🤓

This week I've been navigating the balance between my artistic vision and feasibility of execution for the user interface of the piece. I've also been working on the software development involved in accepting user input through button presses.


Software Development

Recent software development efforts have been focused on button logic. The control panel interface will have two purposes:


  1. Time set control (should only need to be used once)

  2. User interface control

I created a class for a momentary switch with a state machine to determine the kind of input it might receive by the user, e.g. short press, long press, double press. And of course before it enters the state machine I added a function to debounce the input so that the electronics would not register multiple button presses even though the user intended to only press the button once.


In the last few days I've realized that I will need to have different kinds of MomentarySwitch classes to register different types of button presses. For instance, the MomentarySwitch class I designed will not register a press and hold for the purpose of incrementing a value multiple times. For example, if we want to set our oven timer to 90 minutes, we shouldn't have to press the increase time button 90x. We know that we can hold the button then it will start to increment first by 1 minute, then 10.


So I will likely have a base class of MomentarySwitch with a set of states (IDLE, PRESS, RELEASE, WAIT) and several sub classes that will handle states differently.


User Interface Design

All this button pressing talk has also gotten me thinking a lot about what the user input would actually look like. To recap, the light fixture design entails two or three outer rings of light reflecting the current time, complemented by a central light in the middle, providing users with interactive capabilities.




Light Display: Outer rings of color light traverse through the spectrum at different rates, representing different granularity of time. The central light can be controlled by participants.


A straightforward user input option involves a basic knob (involving an additional software design effort) to control the cycle time of the central light. However, I'd also like to offer participants a way to influence the color as well.


The user interface should be simple, clean, and intuitive. I was initially really attached to the minimalist design illustrated in Version 1. There would be a knob on the left that would control the cycle time and a set of increment decrement buttons to control... something. Alternatively, the up and down buttons could cycle through a set of pre-defined color schemes. But with pre-defined color schemes, there would really be no reason to have the buttons represent increment or decrement.




Version 1: The initial concept for participant interaction with light display. A knob selects cycle time and two triangular buttons control an aspect of visual effect. This design was discarded due to limitations in user control while maintaining intuitive design.



I started to wonder, "What aspect of color could the user feasible control with only an increment and decrement button?" I could program some logic that involves pressing multiple buttons at once. But then the control wouldn't be intuitive. So I came up with the design in Version 2 where the middle switch is an RGB LED 3-way rocker which would serve as an RGB color select. The user would select which aspect of the color they want to change for the spectrum, then they would increment or decrement the overall values of red, green, or blue.




Version 2: Left-most switch is a knob to control cycle time as indicated in Version 1. The middle switch is a 3-way rocker for color selection. Triangular buttons increment or decrement color selected by rocker switch. Either rocker or triangular buttons illuminate in red, green, or blue, reflecting user selection.



I knew that there was a slim chance that an RGB LED rocker switch would exist without having to make one myself. So then I decided that the increment and decrement buttons could be RGB and that they would reflect the color selected from the rocker switch. How hard can it be to find RGB LED triangular arcade buttons? Well, it turns out that I can't really find these either.


My quest for RGB LED arcade buttons revealed only round options. For aesthetic purposes, it is important to me that there be shape differentiation between the switches for cycle time control and color select. And I'm pretty attached to triangles for increment and decrement. So, I've come up with the design in Version 3 where I'm now using a round RGB LED button for color select and a slider for cycle time.







Version 3: The left-most switch is a slider used to control the cycle time, the center button will illuminate as either red, green or blue, and the right set of triangular switches will be white or grey.



The control panel design will likely continue to evolve as I search for slider switches that align with my vision, but for now I need to put some of these buttons on order. And in the mean time I need to expand my software to account for new switch input behavior.


bottom of page