IlluminANCS

This original idea was to built a visual notifier for an elderly relative with hearing impairment who often misses incoming calls and messages on their iPhone.
The projects makes a bright, ambient light notification lamp with these features:
- Large and visible from across the room.
- No tiny screens or fiddly apps.
- Automatically syncs with their iPhone via Bluetooth.
- Glows and animates in different colors depending on the notification type
This gives a simple, reliable way to notice calls and messages that could otherwise be missed!
Update 16 Sep 2025
Updated led_ancs.c and led_ancs.h to add strobe light. To select between chase mode and strobe mode see Software Environment and Build section
Update 30 Sep 2025
Replaced host stack Bluedroid to NimBLE which made a big improvement in Bluetooth stability. The previous problems with lost bonds etc seems to be gone. I strongly suggest to use this instead of Bluedroid. I keep both in this instruction so you can compare if you want. Files and some new add-ons, see further in NimBLE chapter.
Also this Nimble implementation was been tested on a ESP32-C3 which works fine and is also a possible option. It has a smaller footprint and takes less space. The only drawback I found with the ESP32-C3 seems to be that the Bluetooth range not as good as ESP32-WROOM-32.
Downloads
Supplies




Hardware Setup
- ESP32-WROOM-32 D1 Mini
- Wemos Mini Power Shield (it does not need to be that specific hardware but this one is cheap and can provide at least 1A on 5V to the LED strip which I believe is a minimum)
- 14-pixel WS2812 LED strip (it can be more or less, the design supports up to 16 LED pixels). The LED strip should be a 5V 60 LED/m type which gives a C-C distance between LEDs of 16.7mm.
- 12V DC power supply providing at least 1A. The selected Wemos Mini Power Shield can take 7-24V DC power so select something in that voltage span.
Software Setup
ANCS BLE Client (ESP-IDF base)
- Built on top of the official ESP-IDF BLE ANCS example.
- Handles bonding with iOS securely (MITM, LESC).
- Subscribes to iPhone ANCS Notification Source, Data Source, and Control Point characteristics.
- Parses category, app name, and message data from iOS.
Bonding Reliability Fix (0x66 issue)
- Original example suffered from lost bonds after long-term disconnections.
- Added backoff reconnect logic and avoided forced advertising after error 0x8.
- Device now stays bonded to iOS even after many hours or connection drops.
Keep-Alive for iOS
- iOS tends to disconnect idle GATT clients.
- Implemented a periodic read task on reading the RSSI level to keep the connection alive.
- Ensures reliable operation without supervision timeout.
LED Control (Circular Strip)
- A 14-pixel WS2812 strip (can be reconfigured to any number between 1-16) arranged in a circle.
- All LED routines implemented efficiently with non-blocking updates to minimize BLE communication issues.
- Effects:
- Solid color on all LEDs. Current implementation us this when BLE is disconnected (red) or connected (blue)
- Chase animation (moving light with tail effect) when notification or call is received
- Strobe animation (bursting light with a pause between bursts)
- Status showing 2 LEDs centered for 10minutes to indicated latest received notification and then go to idle blue
Color mapping
Color mapping is based on notification category (call, message, social, etc.). The ANCS specification divides notification currently in 12 different categories. The led color mapping I have selected is:
- 00 : Green : CategoryIDOther
- 01 : White : CategoryIDIncomingCall
- 02 : DarkRed : CategoryIDMissedCall
- 03 : Cyan : CategoryIDVoicemail
- 04 : Yellow : CategoryIDSocial
- 05 : DarkOrange : CategoryIDSchedule
- 06 : Orange : CategoryIDEmail
- 07 : Magenta : CategoryIDNews
- 08 : Aquamarine : CategoryIDHealthAndFitness
- 09 : DeepPink : CategoryIDBusinessAndFinance
- 10 : Violet : CategoryIDLocation
- 11 : Brown : CategoryIDEntertainment
These colors are defined in the led_ancs.h file (see next chapter) and can be changes based on your preferences. A online tool like rgbcolorpicker is useful. For my purpose I selected white for CategoryIDIncomingCall since it was most important and is easiest to distinguish from the other colors.
Software Environment and Build
- This build is based on ESP-IDF v5.5 of the ESP-IDF.
- Install the ESP-IDF environment from Espressif. It can be installed both on Windows and Linux and macOS.
- Run through the installation adding all necessary tools according to the instructions.
- Are you are not familiar with the ESP-IDF toolchain run the "Hello World" example. It is easy and it ensure that you have everything installed correctly and that the ESP32 connects to the right port for flashing and monitoring etc. It will save you time.
- When all set, download the code to a folder similar to the "Hello World" example structure, name folder to illuminANCS.
- Due to restrictions what files can be shared some additional file structure is needed.
- Rename sdkconfig.txt to sdkconfig.default and put in illuminANCS folder
- Rename CMakeLists_root.txt to CMakeLists.txt and put in illuminANCS folder
- Put README.txt in illuminANCS folder
- Create a main folder under illuminANCS
- Rename CMakeLists_main.txt to CMakeLists.txt and put it in main folder together with the remaining files.
- Compare your file tree with above
- Also in order to make the compilation go through add for that directory the led-strip dependency:
- If you want chase animation or strobe animation select it in led_ancs.c file by comment out the unwanted animation:
- Compile and flash the project onto the ESP32 in the same way as the "Hello World" example.
- On your iPhone the ESP32 will advertise as "illuminANCS" and you will find it in the list of devices under Settings->Bluetooth on your iPhone.
- The pairing can sometimes need some toggling of Bluetooth on/off in iOS but shall work stable once it paring has been successfull and notifications has been been allowed.
- When all this is set you should be able to see the current notifications in the monitor on the laptop.
If you have passed all steps successfully it is time to add the LED strip and do some wiring.
Do the Wiring

Wiring
The wiring is very modest since there is only VCC, GND and data signal to LED strip that is needed. See schematic.
5V
Since LED strip is very power hungry and at some stage you will need to connect the ESP32 for programming is not good to at the same time power the LED strip from your laptop. To prevent any damage I created a harness on 5V that to ESP32 that can be disconnected when its connected to the laptop. In the schematics it is called S1 but is actually just a male-female connector on the cable.
When all this is wired you can power the ESP32 with the LED strip and see if it works. You can runs the LED strip as the same time as you have the monitor to the laptop connected just make sure that the S1 is disconnected.
You can now do the printing of the enclosure.
Enclosure 3d Print and Assembly




Parts
The 3D print contains of 4 main parts:
- Top
- Bottom with ventilation
- 4 x Light-guides
- Diffusor glass with hole for DC jack
Filament
I printed part 1-3 in black PLA and part 4 in transparent PETG. This was what I had in my lab but I believe any combinations of filament will do (as long as the diffusor glass is transparent and lightguide is dark/black)
Lightguide
The reason for having a light-guide is that it separates the LEDs and make it possible to distinguish between what is lit and at what color. Also instead of having a solid ring I printed them as straight segments with a wafer structure which makes it possible to bend them on the inside of the diffusor. This 4 pieces are also easier to sprint on a small printer and due to it flexible design the fitting do not need heating to bend and can be tailored to a larger extent than just a solid piece.
Also if another LED strip type is used say 30LED/m the only thing to re-design and print is the lightguide which takes 30min to print and consumes very little filament.
Assembly
Both the Power Shield and the ESP32 is secured with glue to the bottom lid. When gluing the ESP32 put it as far to the side as possible to make it possible to access the USB-mini connector. Let the connector be fitted when you glue to know. Also when gluing the Power shield mount the diffusor glass and DC-adapter to make a proper fit. Make sure the gluing feels solid since over time the DC-jack can be subjected for a lot of wear.
Bottom and lit are fitted together using 2 pcs of 3x12mm screws. Also 2 adhesive furniture pads are fitted on bottom side to improve ventilation since the unit can consume up to 5W.
Future Possiblities and Tips and Tricks
- The Espressif implementation is a well structured code and is a solid implementation. However BLE and iOS can be a challenge with dropped bonding and broken pairing. This code add-on is as good as it gets from me currently. I have added a way to avoid start of advertise in order loose bonding and to prevent the so-called 0x66 issue but further improvements can always be made. See forum or ask ChatGPT if you face any future challenges.
- A way of testing the illuminANCS is to create notifications locally using Shortcuts which is a standard App installed on iOS. It has been very helpful throughout the development. Search for Apple + Shortcuts to find guides how set it up and use it as a test tool or when demonstrating your IlluminANCS for your friends!
- Unfortunately ANCS is only supported by iOS and do not exist on Android. An Android will see the BLE advertise but when connected nothing will happen. If going for a solution that works instead on Android an additional Android App is needed or using Bluetooth Classic using Hands-Free Profile (HFP) which will notify and handle calls at least.
- The Espressif code supports everything that is in the ANCS specification which is actually overkill for this project but I have kept is as it is. A possible add-on is to use display to show all the content of the Notification i,e, Title, Sub-Title, Message, Date and/or accept or reject calls with buttons on the enclosure show RSSI level etc.
- Also new animation effects are fun to add ie glow lights and many more
- Another future possibility is through Shortcuts and the possibility to create your custom notifications system configurations can be done by sending for example "illuminANCS Setting : 1" as an Title which sets the animation effect to something else and stored persistent in flash.
NimBLE

Download, structure and build this in the same manner as described in Step 1: Software Environment and Build
Also rename Kconfig_projbuild.txt to Kconfig.projbuild and put in the main folder. This config makes it possible through menuconfig to set:
- IO pin number (default is 16)
- LED strip length (default is 14)
- Strobe or chase mode of animation (default strobe)
Open menuconfig using
The settings are found under "illuminANCS configuration"