United States - Flag United States

Please confirm your currency selection:

Bench Talk for Design Engineers

Bench Talk


Bench Talk for Design Engineers | The Official Blog of Mouser Electronics

Mouser’s STEAMy Summer: Part 3 Mike Parks

The dog days of summer are almost over for those of us here in the northern hemisphere. But while this fun, carefree season was here, the sun shined most days and with it came potentially harmful ultraviolet (UV) radiation. In this final article of the series, we will construct our circuit and program the Arduino MKR1000 to perform the functions we established previously. Also, be sure to read the second blog in this series to better understand the science behind safe fun in the sun.

For a quick refresher, these are the top-level requirements for your UV monitor and alert project. Your device should:

  • Detect UV radiation exposure levels continually.
  • Determine if an exposure has exceeded a pre-specified limit.
  • Trigger a fun and whimsical alert, if the exposure limit is exceeded.
  • Be able to reset the exposure count.
  • Be battery operated.
  • Send exposure data to the cloud for future analysis (Note that this step is useful to teach kids how to read charts and graphs.)

In short, the goal for this project is to build a device that monitors our exposure to the sun and let’s us know when we should either take a break indoors or slap on some more sunscreen. Here is the bill of materials (BOM) in a pre-built shopping cart, if you missed it in the previous blog. With that said, let’s get started!

Assembling the Hardware

You may recall from part 2 of this series that we will use the Silicon Labs Si1145 sensor to monitor our sun exposure. We will communicate the sensor’s data via an I2C serial interface to an Arduino MKR1000 embedded development platform. The MKR1000 will handle data processing and communications to a cloud database to store all data for later analysis. The MKR1000 can also conveniently receive power using a lithium polymer (Li-Po) battery, which will allow us to take our device outdoors while we enjoy the sunshine.

Here is a quick synopsis of the steps you and your young, aspiring engineer will take to build this circuit (The hardware schematic in Figure 1 and circuit diagram in Figure 2 also provide visual illustrations.):


  1. Place the MKR1000 on the edge of the breadboard and ensure that the micro USB port is hanging off the end. To indicate the only pin on the MKR1000, use a white stripe, as this is the ground pin.
  2. Place the Si1145 UV sensor (with the header pins) on the same side of the breadboard as the ground pin on the MKR1000.
  3. Wire the ground pin of the MKR1000 and the ground pin of the Si1145 UV sensor to the ground (blue) rail of the breadboard.
  4. Connect the Vcc pin of the MKR1000 and the Vin pin of the Si1145 UV sensor to the power (red) rail of the breadboard.
  5. Connect the I2C ports of the microcontroller and the sensor together. Wire the D12 (SCL) pin to the SCL pin on the Si1145 UV sensor. This is the shared clock signal. Then, wire the D11 (SDA) pin to the SDA pin on the Si1145 UV sensor. This is the shared data bus between the two devices.
  6. Test the connections established up to this point just to ensure that you have wired everything correctly. To do this, go to Mouser’s GitHub site and upload the Arduino STEAMYSummer2018_MRK1000.ino file and the Wifi_Info.h file. Once you have successfully loaded the code, fire up the serial monitor for the Arduino Integrated Development Environment (IDE) and ensure that you are getting visible, infrared (IR), and UV sensor readings. If you are not seeing a green light-emitting diode (LED) on the MKR1000 or are getting the error message “Cannot find the Si1145” in the serial monitor, be sure to check the wiring diagram again (Figure 2).

Figure 1: This hardware schematic illustrates the pin setups. (Source: Author)


Figure 2: This circuit diagram illustrates the breadboard layout. (Source: Author)


With the first part of the hardware setup complete, let’s turn our attention to the user interface components. Recall that for the alert, we will use a piezoelectric buzzer that is sure to grab the attention of whomever is nearby. Specifically, the buzzer of choice is TDK Corporation’s PS1240P02BT because of its 3V operation. We will also add a resistor and transistor to help power the buzzer and ensure that it drives enough current to make the buzz noticeable. Current from the general-purpose input/output (GPIO) pins is limited to 7mA. The microcontroller’s GPIO pin (“D6” pin) should turn on the transistor and allow you to:


  1. Place the NPN transistor on the breadboard.
  2. Connect the red wire of the buzzer to the power (red) rail.
  3. Connect the black wire to the collector pin of the transistor.
  4. Place a 1kΩ on the breadboard to connect one lead to the base of the NPN transistor and then connect a wire from the other resistor lead to the MKR1000’s D6 pin.
  5. Wire the emitter pin of the NPN transistor to the ground (blue) rail of the breadboard.


Recall that we need a way to reset the device once an alert is triggered. To accomplish this requirement, we selected a normally open (NO) momentary pushbutton. A 10kΩ pull-down resistor will be used to ground the button that is wired to the microcontroller GPIO pin to prevent any floating input. Let’s wire those in now (Figure 3):


  1. Wire up the pushbutton next, hooking one side of the button up the power (red) rail.
  2. Connect one terminal of the 10kΩ resistor to the other side of the button.
  3. Connect the remaining terminal of the resistor to ground.
  4. Connect the MKR1000 D7 pin to the junction of the resistor and pushbutton.

Figure 3: This printed circuit board (PCB) image illustrates the layout. (Source: Author)


The resistor serves as a pull-down resistor, ensuring that the GPIO pin on the MKR1000 always sees a clean ground state when the button is not being depressed. Without the resistor, the pin is susceptible to noise that may result in the microcontroller incorrectly detecting a button press.


Using the Software


Mouser’s open libraries for this project contain the following tools, resources, and functions:


#include <Wire.h>

Provides the code necessary for use of the I2C serial communications protocol.


#include "Adafruit_SI1145.h"

Gives an easy to use set of functions for interacting with the ambient light sensor.


#include <WiFi101.h>

#include <WiFiSSLClient.h>

Allows secure Wi-Fi communications.


#include "Wifi_Info.h"

Stores the service set identifier (SSID), Wi-Fi Protected Access II (WPA2) password, and the IFTTT (which is a tool we will discuss later in this article) application program interface (API) key. It’s a good habit to put these secure items in a separate file so that if you share your code, you don’t have to remember to remove these sensitive pieces of information each time you wish to share a revision.


Figure 4 provides an example of the source code, which is written in the Arduino IDE.

Figure 4: This is source code, written in the Arduino IDE. (Source: Author)


Key Variables


static const int DELAY_AMT = 60000;

This variable equals 60,000 milliseconds or 60 seconds. It allows us to limit the number of sensor readings to one per minute.



static const int AVG_ARRAY_SIZE = 60;

Since we are concerned with the average UV reading over the previous hour, and we are taking one reading every minute, this variable will enable us to average the 60 readings we need to find the current average UV index over the last hour.



static const int BUZZER_PIN = 6;

The buzzer will operate under the control of the MKR1000’s GPIO D6 pin.



static const int RESET_BUTTON_PIN = 7;

The reset button will connect to the MKR1000’s GPIO D7 pin.



static const float UV_THRESHOLD = 3.0;

If the last hour’s average UV index reading is 3.0 or greater, it will trigger an alert.


static const int TONE_FREQ = 2500;

The triggered alert will generate a tone of 2,500Hz with the buzzer.


char ssid[] = "MY_SSID_HERE";

In the WiFI_Info.h file, be sure to replace this default with your local Wi-Fi SSID. Be sure to keep the quotation marks.


char password[] = "MY_WPA2_KEY_HERE";

In the WiFI_Info.h file, be sure to replace this default with your Wi-Fi password. Be sure to keep the quotation marks.



In the WiFI_Info.h file, be sure to replace this default with your personal IFTTT API key that you will generate when you create a webhook for this project. Be sure to keep the quotation marks.




void setup()

The void setup()function is a requirement, where all the initialization will occur. This initialization includes establishing a debug serial communications channel, setting up the Wi-Fi module and the Si1145 ambient light sensor, and ensuring that the GPIO pin configurations for the inputs or outputs are appropriate.



void loop() {

  float currentUVindexReading = takeReading();

  float avgUVindexReading = runningAverage(currentUVindexReading);






The entirety of the main loop()function is presented here to highlight an important programming paradigm. The main loop should contain as little code as possible. In fact, it should be the goal to breakdown the code so that each function does one thing only. Rely on function calls to make the code more readable and easier to troubleshoot. From the void loop()paradigm above, it’s easy to create a synopsis of what will occur after the MKR1000 finishes the tasks prescribed in the setup()function.


The synopsis should flow as follows: First, a sensor reading is necessary to store in the variable called currentUVindexReading. This value passes to another function that records the new UV reading and returns the running average. The revised running average will then pass to the function that will send it to IFTTT to append to a Google Sheets spreadsheet. Next, a comparison of the average against the threshold will occur, and the results will trigger an alert if necessary. Finally, the system must pause for one minute, and then this function will repeat itself.


Here is a code breakdown of each incremental function in the main loop:


float takeReading()

This function interacts with the Si1145 ambient light sensor. It receives a reading and displays the results on the serial port before returning the UV index value as a floating-point number.


float runningAverage(float newReading)

This function keeps a static array (meaning the values are preserved after the function call returns) to track the running average of the UV index over the last year. It returns the current average UV index as a floating-point number.


void alertCheck(float avgUVindexReading)

This function compares the current average UV index against the predefined threshold and initiates an alert if necessary.


void generateAlert()

This function uses the tone() function built into the Arduino IDE to generate a tone with the buzzer. It continues until a press on the reset button, at which point the average UV index resets and the device goes back to monitoring mode.


This function leverages the IFTTT.com webhook API to pass the current UV index reading to a Google Sheets spreadsheet, enabling you to study the data remotely.


Putting It All Together

We will leverage a web service called IFTTT (short for “If This Then That”) to allow the MKR1000 to communicate to Google Sheets (Figure 5). Specifically, the IFTTT service is referred to as “Maker Webhooks.” IFTTT provides a great tutorial on their website for how to use their service. The result is a data log and a nice-looking chart to help visualize the data. We recommend that you read through the documentation section for webhooks on the IFTTT website, as you will be required to include a key specific to your IFTTT account in the Wifi_info.h file.

Figure 5: The MKR1000 sends its data to Google Sheets via IFTTT. (Author)


An EagleCAD schematic and printed circuit board (PCB) layout have been provided to assist you if you desire to take the project off the breadboard and put it through its paces outdoors. We have also provided a 3D-printer-ready STL file as an enclosure to house the hardware (Figure 6 and Figure 7).

Figure 6: This is a 3D rendering of the circuit board shield. (Source: Author)


Figure 6: This 3D printable project enclosure houses the hardware. (Source: Author)


Lastly, the design files and source code are available on Mouser’s GitHub repository

« Back

Michael Parks, P.E. is the co-founder of Green Shoe Garage, a custom electronics design studio and embedded security research firm located in Western Maryland. He produces the Gears of Resistance Podcast to help raise public awareness of technical and scientific matters. Michael is also a licensed Professional Engineer in the state of Maryland and holds a Master’s degree in systems engineering from Johns Hopkins University.

All Authors

Show More Show More
View Blogs by Date