Software apps and online services
Hand tools and fabrication machines
BOFF is an Internet connected Smart Fan. It's Alexa enabled through the Alexa Smart Home skill and provides interesting visualisation of environmental conditions (or just gentle mood lighting if you prefer!) along with a nice cooling breeze of air.
The aim of this project was to build an open source, Internet connected Smart Fan, that could be controlled remotely and would sense environmental conditions allowing it to report back issues (feel sleepy in meetings? Maybe the CO2 level is high).
Importantly it is designed to be hacker friendly, an open design that is relatively easy to build and modify. Don't like the enclosure, you'd prefer 2x2 arrangement? or just 2 fans? Sure, adjust the case and you're away. Want to add carbon or other filters, sure, hack the outlets to add a holder in.
Many people like a gentle breeze when getting to sleep, or when waking up, likewise nightlights are also very popular. However you may prefer to turn them off before falling asleep, and nobody wants to get out of bed to turn a fan off, by enabling Alexa integration our comfy sleeper can ask Alexa to turn off the fans and not have to get out of bed.
BOFF has been designed around commodity PC fans. If you are into building your own PC you've probably got a few kicking around, I had a box full, as does my local maker space! These run from 12V DC so no dangerous mains voltages kicking around.
Whilst I had originally intended to use some of the many fans, shortly after starting this project I discovered the LL120 by Corsair. Not only are these nice and quiet (practically silent on low speed) but they also feature 16 RGB LEDs, 12 around the outside and 4 in the central hub. Yes, 16 individually controllable RBG color changing LEDs on a fan and for bonus points they appear to be standard WS2812 Neopixels so easily connect to an Arduino with driver libraries already available. I couldn't resist!
The enclosure is a fairly simple laser cut design. I've built two versions, a maker style clear acrylic version (lets you see the insides!) for my office and a more home friendly version from ply wood which blends in nicely with my book case in the living room.
The box was designed using MakerCase, the attached json file can be uploaded and modified as desired, I used T-Slot settings, but sadly the default 10mm machine screw length combined with 5mm acrylic resulted in the nut not being retained, so I reverted back to Tensol 12 to glue the acrylic together and wood glue for the ply.
I didn't glue the back panel of the acrylic enclosure, but left it in place whilst the glue set for the front panel glue to keep the shape as it's a really tight fit.
Finger guards are also made from laser cut acrylic (3mm) with laser engraved patterns on to indicate the fan visualisation function.
The fans are controlled by an Arduino MKR1000, this connects to WiFi then to the Tinamous.com MQTT server, it stays connected whilst powered on, and subscribes to the status message topic for messages sent to the device. This allows Alexa, and other users in my Tinamous account to post a status message (like a Tweet) which can then be processed by the Arduino.
Likewise the Arduino can publish measurements via the MQTT channel for environmental conditions, status, fan speeds etc.
The skill uses the standard Smart Home interface so no custom utterances are used (although adding these would allow the functionality to be extended, such as, setting the display visualisation for each fan, or controlling fan speed and led brightness at the same time), setting a wake up time for the fans to start.
Once the skill is enabled the user is prompted to do a Smart Home discovery, here it queries your Tinamous account for devices tagged with Alexa.SmartDevice. Each device that has that tag is then set-up as a Smart Home device.
The devices are named by using the devices Display Name, allowing more friendly names than you might have used for a username, this also makes it easy to change the name should you need to (Protip: Don't call your fan, "Wooden fan", even if it's in a wooden box, Alexa will insist you are saying "Wooden fence", which is no doubt more popular than a wooden fan, but trying to set the brightness on a wooden fence is not so easy).
Additional tags are used on the device to indicate display categories (Fans, Lights, etc) and capabilities. Where the skill sees a device with a known smart home interface (i.e. Alexa.PowerController) it will add that capability to the device.
Setting Alexa.TemperatureSensor enables the device to act as a temperature sensor, it also needs a field named, or tagged "Temperature".
After the device has been added, Alexa can then handle Smart Home utterances, such as "Alexa, Turn On The Fans", this will look for a device named "Fans", then send the "Turn On" instruction through a Alexa.PowerController interface.
When the skill receives a known directive (i.e. Turn On) it sends a status message to Tinamous directed at the specific device (e.g. @OfficeFans Turn On), the Arduino MQTT client will receive this and can then handle the turn on command.
However this style of communication means that should the device not be online, or have a fault it won't be reported back to Alexa.
The status messages appear to come from me as I authenticated Alexa as myself. I could have made a different member account at Tinamous specifically for Alexa. Likewise, any member or device that has permission to post a status message can control the fan through simple commands.
Sadly I've been unable to get Alexa to differentiate between Alexa.PowerLevelController and Alexa.BrightnessController commands, once the brightness controller is enabled, power level commands come in as set brightness, so either the fan speed or light level can be controlled via Alexa Smart Home, but not both.
The skill is written in C# for .Net Core 2 and can be downloaded from Github. Other than changing the json file for your Lambda settings it should be usable "out of the box" and deployed under your own skill to interface with any devices you may have connected in Tinamous which can subscribe to an MQTT feed.
Be sure to use the WiFiSSLClient library for the Arduino WiFi, you won't be able to connect on port 8883 for MQTT without it and you won't have a secure connection. If you are using 1883 for MQTT your connection is not secure!
You'll also need to add the Tinamous.com certificate to your Arduino to be able to connect securely.
BOFF detects the sensors attached at startup and use these to gather environmental conditions. These include:
BME680 for temperature, humidity, pressure and air quality. I've used the Pimoroni breakout board for this and it's fitted onto the outside of the enclosure to prevent cooling from the fans. Where the Amazon Dot holder is used it's tucked away in the back of that (Although it does appear to suffer from heating from the dot, so a redesign is needed there!).
This VOC sensor needs about 30 minutes to provide meaningful readings after power on as you can see from the chart below. Fortunately the Arduino MKR1000 has battery support which will allow the sensor to remain powered whilst the fan is disconnected (and even continue to measure and sensor measurements).
BME280 for temperature, humidity, pressure. The BME680 is preferred but these can be hard to get hold of so a fallback connector for the 280 is provided.
CCS811 for air quality where the BME680 is not used, or for a second air quality measurement. These need temperature compensation so the BME280 should also be fitted.
TCS3472 for light level. This uses the ThingySticks Arduino Environmental cap, and this sits on top of the Arduino (assuming you've got the header version) and measures light level, which includes individual RGB levels as well. As this sensor is fitted on top of the Arduino it's not much use in the wooden box version. This could be used for brightness control of the LEDs, or to set BOFF to sleep mode when all the lights to out.
MMA8452Q accelerometer. This isn't actually enabled at this time, but it's fitted with the Environmental cap, it might prove interesting down the line for vibration sensing as an indication of fan problems, or perhaps detected a tap on the fan case to start the fans.
Fan tachometer. Each fan has a tachometer output, these pulses are counted by interrupts on the Arduino the speed (RPM) is then computed. I had problems with fan 4's tach into the SCK pin causing the Arduino to latch up when the fans were started so this has not been enabled (pin removed from connector). The PC fan specification is for the tachometer output to be an open collector which means we pull the signal up to a desired voltage with a weak pull up resistor (i.e. 3v3 though the Arduino INPUT_PULLUP) and each pulse will bring the level down to ground. This means the Arduino is not exposed to 12V (or even 5V) from this signal. However, not all fans observe this so check the fan before connecting to the Arduino!
Fan supply voltage is sensed through the potential divider made of R2 (43k) and R3 (10k) to bring the expected 12V down to a level the Arduino ADC can measure (pin A6), about 2.2V.
Dust sensing is not implemented but has space on the control board for the 3 pin PWM type sensor. This needs more investigation and other sensors need more pins which were not available on this version.
Switches - Two switch inputs are provided with LED drives as well for switches should this be desired.
Missing: No sensing is done on power consumption, this would have been a nice addition, particularly for the 5V supply that drives the LEDs as these can get very power hungry, likewise sensing on the 12V fan supply might help diagnose pending fan failures.
That's a lot of sensors! Not all of these are of interest to the end user so they are filtered out at Tinamous to include just the interesting fields for display with other fields being actionable but not shown all the time (i.e. fan supply voltage).
Each of the four fans can be configured to display a certain visualisation parameter. These include: Temperature, humidity, air quality, WiFi strength, time, fan speed, light level, fixed color or a funky pattern.
It goes to 11!
Whilst many visualisations only go to 10, BOFFs goes to 11! The fans have 12 pixels around the outside, the top (12 O'Clock) position is used as the central "Zero" point with the remaining 11 pixels showing the offset. Each visualisation has a pre-set range that these 11 pixels show, either side of the ideal value.
When the measured value is at the ideal value the whole fan face is set to green, but as the measurement moved away from ideal the pixels are lit based on a pre-defined range going from the 12 O'Clock position, either clockwise for above or anti-clockwise for below.
Whilst the measured value is within a ideal (comfortable) range, the pixels will be lit green, below range they will turn blue, and above range red.
This display is configured that the ideal temperature is 22°C, with a min and max range of 2.5°C either side. So the 12 O'Clock led would be 22°C, then 11 LEDs to represent 2.5 (0.22°C each). The ideal range is set to +/- 1°C so a temperature in the 21-23°C will result in a green fan/nose, Below 21 and above 23 will be blue and red respectively and below 19.5°C and above 24.5°C will result in a full blue or red fan.
Below the first image shows the fan showing a temperature that is comfortable (green outer and green nose) but below the ideal temperature (the 12 O'Clock position with the display going anti-clockwise around to the 7 O'Clock point), this is about 21°C.
The second image in the set shows an over range (hot) indication, and the third image shows a green band from the ideal 12 O-Clock through to 4 O'Clock position indicating above ideal but still comfortable.
The other visualisations (Humidity, WiFi signal strength etc) work exactly the same way.
Others visualisations worked out much simpler, The clock for example. 12 pixels around the outside worked out perfectly for a LED fan clock!
Alternatively the fans can be set to just show a funky pattern or fixed color with no real meaning.
What do you do when you've alredy got 64 LEDs and a clear acrylic case? Add more LEDs! Obviously!
A recent addition to the Neopixel strip range are the side light strips, these have been used with great effect on the fan.
There are two sets (mainly because they come in 1M lengths and the main outer strip needed slightly more than 1M so I had some left over).
Strip 1, as it's called in the software, is a vertical facing strip attached to the inside back wall, this is used to bounce light off the ceiling to provide general background mood lighting.
Strip 2 goes around the fans facing outwards, this is used to indicate interactions with Alexa, provide some animations (fan speed) and Alexa controllable mood lights.
These two strips add an extra 223 LEDs to our setup, the little 1A 7805 style buck regulator on the PCB is unable to cope with these at anything other than minimum levels (actually, as do my eyes, their very bright!). The PCB is designed such that Fan 1 LEDs get their power from the on-board regulator via a diode dropper (so we can get away with 3v3 logic), but fans 2-4 and strips 1 & 2 (fans 5 & 6 on the schematic) can get power either via a jumper for on-board or via a terminal block for an external 5V converter (these are plentiful on eBay for a few dollars).
With just the 4 fans (64 LEDS) and driven at 50% or lower the on-board regulator copes well, but anything more and the second regulator is required.
Ahh yes, well, moving along swiftly....
As you can see the fronts (air intake) of the fans are covered by finger guards which also provide indication to the fans display, this naturally restricts the air flow. These are about 20mm away from the fan so the air has to come from the edges.
Inside the box, well no structure is provided to guide the air but this should be a simple addition with some 3D printing.
Air outlets are in the top of the box. As you can see from the photos and videos I'm experimenting with different vents. The idea of an open design like this is you get to make what you want. Air flow straight up in the winter to try and push the hot air away from the ceiling, air flow as a small jet towards me in the summer for cooling? Air flow design has defiantly been left out of this fan! But never mind, have you seen the LEDs!
The 3D files with this in the project include various outlets, including two blanking plates which hold a Dot at an angle and one for the Echo with a cable outlet designed in.
Ohhh theirs a fair few things to list here....
Many PWM fans (the 4 pin variety) don't stop on the minimum PWM value, they run at the minimum speed, so we need additional power switching if you want them to actually switch off, this is done through Q3 and Q4 for all the fans, it would be nice to have that split between Fans 1 & 2 and 3 & 4 to allow a greater control (not for this project but other projects based on the fan controller).
Likewise Q4 is rated at about 2 Amps, if we run powerful fans it could easily be double that current, so a bigger fet is needed.
More capacitors! You may notice in the photos I've had to use a big electrolytic input capacitor, when the 4 fans kick in they can take a big chunk of the supply and cause the Arduino supply to drop enough to reset it.
Bigger capacitors for the Neopixels. I used to smaller pads on the PCB for C4 and C5.
Originally I used individual PWM signals for each fan, of the three use cases I've used the controller for now I've never needed this, a single PWM signal would have been enough, and this would free up a number of pins.
Fan tachometer input does weird things on the SCK pin for fan 4, I've tried various things but it really doesn't like that pin.
Fan PWM frequency should be about 25kHz, this is way above the PWM frequency of the Arduino and it's not simple to change (it's possible, but I wasn't sure of side effects so didn't hack down to that level). When running 3 pin fans (i.e. Fan 5) below the 25kHz the fan is noisy.
Fan 5 was added as either a means to draw air over the sensor when the main fans were not running, or as an air flow sensor (by measuring the tachometer output with the fan not powered). However I've never used this so it can be dropped freeing up 2 more valuable pins on the Arduino.
Alexa SmartHome Skills don't differentiate between brightness and power level when the Alexa.BrightnessController and Alexa.PowerlevelController are both enabled. Power level commands come in as set brightness which isn't great when you need to change the fan speed, and the brightness.
Alexa skills are mighty painful to debug, some tips:
- Ensure your Lambda is in the correct region (Ireland for UK English).
- Use matching email accounts between Alexa and AWS (Not sure if this is required but it appeared to make a difference).
- Put lots of logging in your skill, you'll only get something went wrong from Alexa.
- If your skill randomly stops working check the authentication token. I got no feedback when my refresh token failed other than stuff just not working.
- Ensure your Lambda has CloudWatch permissions, if you follow examples it might not and you'll not get logs.
- Don't use the blueprints for SmartHome in Lambda, these are for version 2 which is now deprecated, likewise theirs only one sample, that's in Node JS and it regularly failed to load in the editor. Github has many better samples.
- Requesting Alexa to set the power level to 0% actually results in a request for 20%. I ended up having to ask for 1% to make the fans stop (they stop below 5%).
The ThingySticks Environment Cap PCB I designed for this project had the wrong pinout for the BME680, combined with an extra 2 week delay to PCB shipping because of customs, when they arrived I was out of the country so I didn't discover the issue until it was way too late.
The fan controller PCBs had the wrong silk screen printed, the fab house used the dimensions layer instead of bNames for the lower silk screen.
Don't have Cura open when you're trying to program the Arduino via the serial port. Cura takes over the port.
Ohh the joy of voice, sometimes Alexa just wants to play silly games with me.... It took a fair few tries to get a good flow of instructions working, Alexa had some fun and games with me in the process...
Because I took loads.....