Software apps and online services
Hand tools and fabrication machines
This is a method of controlling and monitoring ultraviolet germicidal lights using Bluetooth communication on an Android device along with a Bluetooth-enabled Arduino. This Bluetooth control module was designed to control the ultraviolet germicidal lights for Project Ultra-Violite by the Lingnan Entrepreneurship Initiative at Lingnan University. The lights used in this project enabled the disinfection of low-income housing in Hong Kong. Volunteers from local non-governmental organizations used the lights to disinfect over 1000 low-income residences in Hong Kong during the height of the COVID-19 pandemic. These Bluetooth-controlled lights were designed to be safe, durable and easy to use. The project was a collaboration between Lingnan University, Department of Social Work and Social Administration of The University of Hong Kong, Caritas Youth and Community Service, and Health In Action and funded by the Hong Kong Jockey Club Charities Trust. More information can be found here: https://www.ln.edu.hk/lei/events/project-ultra-violite
This project can be used to control any ultraviolet light (or traditional lights as well), but was specifically designed and tested with the Project Ultra-Violite lights. Instructions for building those light units can be found here: https://www.hackster.io/lingnan-entrepreneurship-initiative/project-ultra-violite-uv-c-disinfection-light-baa372Important safety information
This project presents risks from using AC mains power, as well as ultraviolet light in the C band.
Using and interacting with mains power is dangerous. The wiring in this project should only be done by someone trained in and comfortable working with mains power. If you are not familiar with the safety requirements of AC mains power, request assistance from a properly trained technician.
Ultraviolet light in the C band is harmful to the eyes and skin. Exposure can lead to blindness and burning. Never operate the lights in a way where you or other living things could be exposed to the light in any way. You must ensure that no one is in the same room as the lights, or in any location where they could be exposed to the lights while they are operating.Overview
This project consists of four main components: A circuit to connect the Arduino Nano BLE to the sensors and UV lights, the Arduino code for interacting with the sensors and the lights, an Android application created using MIT App Inventor to interact and monitor the lights, and a 3D printed mount to attach the controller to a tripod.The Materials
The lights use common commercially available hardware, with some optional 3D-printed parts to aid in assembly. Let's go over the details of the parts needed to make the lights:
- Arduino Nano BLE Sense. This microcontroller is used to interface between the Android application, the lights and the sensors. It was chosen primarily for its Bluetooth capabilities. Any Bluetooth Low Energy-enabled Arduino will work for this project.
- PassiveInfraredMotionSensors. These sensors are used to determine if any person or other living thing is near the lights during operation. If the sensor is tripped, the lights are automatically turned off. Each sensor has a field of view of around 100 degrees, so using three mounted in a circular pattern gives nearly 360 degrees of coverage.
- GUVA-S12SDUltravioletSensor. Used to monitor the status of the lights, whether they are illuminated or not. This allows users to ensure that the lights have been turned on as expected, so that the target space has been disinfected. It also give users an indication if the room is safe to enter by displaying if the lights are on or off.
- 10A250VRelay. Used to trigger the lights.
- 8Channel Bidirectional Level Shifter. Used to adjust the signal voltage between the Arduino Nano, which operates at 3.3V, and the relay which operates at 5V. The 8 Channel level-shifter was chosen for this project to account for the possibility of using more 5V sensors or relays. However, for the project in its current configuration, only one channel is needed.
- Hilink HLK-PM01 5V AC/DC Regulator. Provides 5V power to Arduino and sensors from the mains power supply for the lights. If you are properly trained and comfortable working with AC power, you can include this regulator in your circuit to power these other components. If not, then another power source such as a small battery or a cell phone charger.
- Android Device. Interfaces with the lights over Bluetooth using the included Android application.
- Protoboard. Platform to construct the circuit.
The core of the circuit is the Arduino Nano BLE Sense. This provides the capability to communicate with the circuit using an Android device over Bluetooth. The Arduino receives information from four sensors - the three PIR sensors and one UV-C sensor. The PIR sensors are connected to three of the Arduino's digital pins, and each are connected to 5V power and ground. The UV-C sensor is connected to one of the Arduino's analog pins, as well as 5V power and ground.
The Arduino has two main outputs, the 10A relay and a status LED. The relay acts as a switch to turn on and off the power to the lights. It is connected to the Arduino through the level-shifter because the Arduino Nano operates at 3.3V and the relay can only be triggered by a 5V signal. The level-shifter is connected to 3.3V power from the Arduino Nano for the 3.3V logic reference, 5V power from the voltage regulator for the 5V logic reference, and a common ground. The level shifter also has an enable pin, which when driven high enables output from the level-shifter. Therefore, it is connected through a 1K ohm resistor to a digital pin on the Arduino Nano. The relay is also connected to 5V power and ground. The live mains power line of the lights runs through the relay, allowing it to be switched on and off.
The status LED is connected to the a digital pin of the Arduino through a 1K ohm resistor. It acts as a visual indicator of the power and connection status of the control unit.
Power was provided through using the HiLink HLK-PM01 5V AC/DC Regulator. This is connected to mains power through a 13 amp fuse. If you are properly trained and comfortable working with AC power, you can include this regulator in your circuit to power these other components. If not, then another power source such as a small battery or a cell phone charger. If you choose to use the cell phone charger, it can be connected to the Arduino through the USB port. The reset of the schematic remains the same. If you choose to use the HiLink HLK-PM01, you may consider using this breakout board from OpenHardware: https://www.openhardware.io/view/504/HLK-PM01-breakout-board. This breakout board adds safety using two types of fuses and a varistor.
You may assemble the circuit on a breadboard, protoboard, strip board or other similar platform according to the schematic included below. While we have not yet created a printed circuit board for the circuit, we have included the preliminary Eagle files if others wish to do so.
As the project includes AC mains power, a proper enclosure is important to prevent accidental contact with the high voltage. We used a generic plastic electrical enclosure with dimensions of 150mm x 70mm x 27mm. We mounted the protoboard, relay and 3D printed parts with hot glue.
We also designed a mount to attach the box and PIR motion sensors to the Phottix P220 tripod used to hold the lights (see our tutorial for constructing the lights here). The CAD files are included in this tutorial, but may need to be modified for enclosures or tripods of different sizes.
The Arduino code is written using the ArduinoBLE library. Bluetooth Low Energy devices can either be Peripheral devices, which act as servers holding for the information being communicated, or Central devices, which query the Peripherals for data, and can modify data contained on the Peripheral devices. In our implementation, the Arduino is a Peripheral device, and the connect Android device is the Central.
Bluetooth Low Energy communication centers around Services, which allow for the organization of the data being communicated between devices. Each service contains multiple characteristics, which hold specific data. In this example, there is one Service (the 'lightService' service), and four Characteristics. There is one Characteristic to hold data concerning whether the relay should be switched on or off, one to hold data concerning whether or not the motion sensors have been triggered, one holding data from the UV-C sensor, and one holding data about whether any Android devices are connected to the Arduino. These Services and Characteristics are defined right at the beginning of the sketch, as shown in the code block below.
Also defined at the beginning of the sketch is the local name. This is important because the Android application will search for a portion of this name when it automatically connects to the lights. For example, our version of the Android application searches for the phrase 'LU_Light' in the names of available Bluetooth devices. If it finds this phrase, it automatically connects. Therefore, the lights that we use are named 'LU_Light_1', 'LU_Light_2', 'LU_Light_3' etc. Therefore, you should choose to set the LocalName to include whatever phrase you program the Android application to search for. More of this is explained in the 'Android Application' section below.
The next section of the code is standard definitions of Arduino pins and initialization of variables:
In the setup section, the Watchdog Timer appears for the first time. The Watchdog timer is used to handle any unexpected disconnections or freezing of the Arduino. This timer counts down for the desired time (in this case 2 seconds). By calling
resetWDT() in strategic locations in the code, we can ensure that the timer does not reach zero. If the
resetWDT() command is never called and the timer reaches zero, this means that the Arduino has frozen or become disconnected before the next
resetWDT() command. Thus, the Watchdog timer restarts the Arduino, allowing us to reconnect to it. This is especially important since it is critical that a user always be able to monitor the status of the lights and turn off the lights when necessary.
The Watchdog timer in this sketch is especially useful because of a known bug with the Arduino Nano BLE using the ArduinoBLE library. See here: https://forum.arduino.cc/index.php?topic=645907.0 and https://github.com/arduino-libraries/ArduinoBLE/issues/33. The Arduino Nano BLE does not properly recognize disconnection events. Thus it is possible that if the Android device disconnects unexpectedly, the Arduino will continue to act as if it is connected, and then it becomes impossible to reconnect and monitor or control the lights. To overcome this, the Arduino listens for a polling message from the Android device. If it receives this message, we know that they are still properly connected, and can reset the Watchdog timer and the Arduino continues operating normally. If the polling message is not received in time, then the Watchdog timer is not reset, reaches 'zero', and restarts the Arduino.
Special thanks to Arduino user dniklewicz for posting the suggestion of using the Watchdog timer.
In the code snippet below,
resetWDT() are functions defined at the end of the sketch. In this snippet, we can see the first use of the resetWDT() function as well. We attempt to start the Bluetooth library. If it fails to begin, we keep the LED blinking to indicate a problem. the
resetWDT() function is used in the while loop to prevent the Watchdog timer from reaching zero and the Arduino from restarting.
In the next section, the Bluetooth service is configured. Next, the characteristics are added to the service, ensuring their data is visible to connected devices. In addition, the interrupts for the motion sensors are attached. If a motion sensor detects motion, it will trigger this interrupt.
The next section begins the loop, which will run repeatedly. In the loop, the Arduino listens for devices to connect. If none is connected, the LED blinks. We see here another
resetWDT() ensuring that the Watchdog timer does not initiate a restart of the Arduino.
The next section handles the motion sensors. As will be seen later in the sketch, for three seconds after the lights are initially turned on, the motion sensors are disabled. This is because we found that the sudden change in light that occurs when the lights turned on falsely triggered the motion sensor. Thus we disable the motion sensors for a short time after turning on the lights. If it has been long enough since the lights turned on (about 3 seconds), we re-enable the motion sensors.
If the motion sensors have been triggered (
motionFlag set to
true by the
motionDetected() interrupt service routine at the end of the sketch), then we change the value of the motionCharacteristic, which will be automatically reported to the connected device and a message displayed to the user. We also automatically turn the lights off by switching the relay. At the end,
motionFlag is set to
false so that it can be triggered again later if needed.
The next section handles the data from the other characteristics. First is the
connectionCharacteristic, which tracks whether or not the Android device is still connected. It does so by listening for a value of
0x01 which is sent by the Android device. This indicates they are still connected, so the Watchdog timer is reset. If the Android device sends 0x00, this indicates that the user wishes to disconnect form the lights.
switchCharacteristic is the 'on/off' switch for the lights. If the Android device sends
0x01, then the user has pushed the 'On' button. Thus the relay is turned on (triggered by a low signal). As discussed above, the motion sensors are also temporarily disabled to avoid false triggers from the quick flash of the lights turning on, and the time is recorded so that the motion sensors can be re-enabled in approximately three seconds. If the
0x00 byte is sent, then the use wishes to turn off the light and the relay is switched off (set to high).
Since users cannot be in the same room as the lights while they are operating for safety reasons, we include a UV sensor so they can verify whether the light is truly on or off. The UV sensor is polled at a desired interval, by default every second. We use a 10 reading running average to determine if the level of UV light exceeds a threshold or not. The variable
uvReadings is a list of ten UV readings, indexed 1 to 10. The readings are collected in 10 steps. At each step, the old reading from the step is subtracted from the total, and the new reading is added. An average is then collected by dividing the total by the number of readings taken. If the average is below a threshold, it is determined that the light is off, and a
0x00 byte is sent to the Android device so to create an indication for the user. If the average is above a threshold, the light is on and a
0x01 byte is sent to the Android device.
The last section are the functions used earlier in the sketch. The first is the function used to enable the watchdog timer. Of note is the is the CRV, which is used to set the timeout time. It is calculated as timeout = (CRV-1)/32768. So if you would like to have a 6 second timeout, you must set the CRV to 196609, since (196609 - 1) / 32768 = 6. This calculation comes from the natural frequency of the crystal used to keep time in the processor, 32768 Hz.
The first section is the code used to reset the watchdog timer. The last is the Interrupt Service Routine used if the motion sensors have been triggered. If you are unfamiliar with Arduino interrupts, you can learn more here: http://gammon.com.au/interrupts. If the trigger occurs during the three second period right after the lights have been turned on, in which we purposefully disable the lights, nothing is done. If not, then the
motionFlag variable is set to true. In the next iteration of the loop, the relay will be turned off and a message will be sent to the Android device indicating that motion has been detected.
The Android application was built using MIT App Inventor 2 with the BluetoothLE extension. The application is designed to be used with a set of three lights. However, it can also be used with just one set or two sets. The main functions of the lights are connecting the Android device to the lights over Bluetooth, turning the lights on and off, monitoring the status of the lights, and handling notifications of motion detected by the lights motion sensors.
When a user opens the application, they are presented with four buttons allowing them to connect to a device, disconnect from a device, turn the connected lights on or turn the connected lights off. The bottom half of the screen shows the status of each of the lights. The name of the light is shown on the left. The connection status is indicate using a 'wireless' symbol in the center. A red 'X' through the symbol indicates that the light is not disconnected. No 'X' indicates the device is connected. A light bulb icon will show on the right to indicate if the light is on. Otherwise, no light bulb appearing indicates the light is off.
The first step is to connect to available lights. When a user presses the Connect button, the application begins scanning for available Bluetooth devices, which it aggregates into a list. During the scanning process, the wireless icon is yellow. For each Bluetooth device that it finds, it queries the name of the device. If the name of the device matches the prefix used to designate the UV lights, in our case we use the prefix LU_Light, then it connects to that light.
Once a light is connected, the name of the device is shown and the wireless icon turns blue.
When the desired number of lights are connected, the lights can be turned on using the 'ON' button. Pressing the 'ON' button causes the Android device to send a
0x01 byte to all of the lights on the
switchCharacterstic described above. When the lights are on, the UV sensors in the lights detect this, and the Arduinos inside the lights send a
0x01 byte on the
statusCharacteristic. This is then indicated on the screen using a light bulb icon on the right hand side of the screen.
Pressing the 'OFF' button causes a
0x00 byte to be sent to all of the lights on the
switchCharacteristic. When the UV sensors in the lights detect that they are not on, the Arduinos send a
0x00 byte on the
statusCharacteristic, and the light bulb icons disappear.
When motion is detected by one of the lights, that Arduino sends a message on the
motionCharacteristic. This triggers the Arduino device to send a
0x00 byte on the
switchCharacteristic to all lights, ensuring that all lights turn off. A message is displayed on the application screen. This message can be cleared by clicking on the 'X' icon.
Whenever the lights are connected to the Android application, the Android device is sending a
0x01 byte on the
connectionCharacteristic. As explained in the Arduino section above, this is to indicate that the devices are still properly connected. When the 'Disconnect' button is pressed, the application sends a
0x00 byte on the
connectionCharacteristic of all lights. This triggers them to disconnect. Although MIT App Inventor includes a 'disconnect' function, this was found to not work reliably with the Arduino Nano BLE Sense, so instead of sending an explicit 'disconnect' command, we send the
0x00 byte, which triggers the Arduino to disconnect itself.
We have included both the.apk file for the app as well as the MIT App Inventor project file, which uses the.aia format. To install from the.apk, simply download the file from below on your Android device. Tapping on the downloaded file will start the installation process. You may need to allow the installation of non-market apps in your device settings. For more information on installing from.apk, follow this guide: https://www.lifewire.com/install-apk-on-android-4177185
Using the included Arduino code and the.apk file is the easiest way to get started. If you wish to modify the application, follow the steps below.Modifying the Application with MIT App Inventor
To modify the application, you will need to first create an account on MIT App Inventor if you do not have one. Then, download the.aia file from below. In MIT App Inventor, click File -> Import and select the.aia file. Opening the file will bring you to the App Inventor workspace, where you can modify the interface from the Designer tab or modify the code from the Blocks tab. The included code is fully documented. To view comment in MIT App Inventor, click the question mark in the upper left corner of each Block.