[{"element_type":"alert","content":"\u003cp\u003eIf you haven't seen V1, then check out my other playground notes by clicking my username link in the top right! There will also be a V3 (which will technically be a new DIY version so not the same version scheme at all) based on Naomi Wu's Open-Source Nukit \u003ca href=\"https://github.com/opennukit/Nukit-Open-Air-Purifier/\"\u003ehttps://github.com/opennukit/Nukit-Open-Air-Purifier/\u003c/a\u003e\nArticle last substantially updated: 2024-04-09 11:00AM GMT\u003c/p\u003e","metadata":{"class":"element row-fluid alert-element build-alert alert-primary","markdown":"If you haven't seen V1, then check out my other playground notes by clicking my username link in the top right! There will also be a V3 (which will technically be a new DIY version so not the same version scheme at all) based on Naomi Wu's Open-Source Nukit https://github.com/opennukit/Nukit-Open-Air-Purifier/\nArticle last substantially updated: 2024-04-09 11:00AM GMT","alert_type":"primary"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003e\u003ccode\u003eBasic premise:\u003c/code\u003e\u0026nbsp; \u0026nbsp; \u0026nbsp; \u003cstrong\u003eAdd lights\u003c/strong\u003e (speed / noise / air-purity indicators, or needless dotstar+neopixel love), use small board to \u003cstrong\u003ereceive tachometer input\u003c/strong\u003e and \u003cstrong\u003edrive 24V fan PWM \u003c/strong\u003esignal from particle sensor, along with \u003cstrong\u003enew inputs\u003c/strong\u003e for \u003cstrong\u003enoise level\u003c/strong\u003e.\u0026nbsp; \u0026nbsp;Plus \u003cstrong\u003eshow off Blockly\u003c/strong\u003e based programming on Adafruit IO, and \u003cstrong\u003eupdate \u003c/strong\u003eas and \u003cstrong\u003ewhen\u003c/strong\u003e the \u003cstrong\u003enew maths functions \u003c/strong\u003ebecome \u003cstrong\u003eavailable\u003c/strong\u003e, but \u003cstrong\u003efor now\u003c/strong\u003e write a quick \u003cstrong\u003eCircuitPython version \u003c/strong\u003ethat illustrates all the desired functionality (to port to Adafruit IO).\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/810/original/IMG_20240325_110128_785.jpeg?1712663297","metadata":{"caption":"Blinkenlights! A string of NeoPixels exit the old filter reset button hole, and snake around the main filter"}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/809/original/IMG_20240325_110234_099.jpeg?1712663280","metadata":{"caption":"The Finished Article - Left = Power board, Middle = ItsyBitsy+Rotary Switch carrier board, right is a w.Fl antenna (Red = AirGain external wifi aerial) and finally an I2C sensor"}},{"element_type":"markdown","content":"\u003ch3\u003eDecisions, decisions... January 2024\u003c/h3\u003e\n\n\u003cp\u003eI need to have something where the original knob / speed-dial went. I've managed to source the original 4-Pole Single-Throw (4PST) rotary switch, which gives 4 positions (off \u0026amp; speeds 1-3), and I've also got a rotary potentiometer to allow full analog selection of the fan speed value. I need to pick one :shrug: or drill another hole for the second one and use both. \u003c/p\u003e\n\n\u003cp\u003eThe original thought was use the potentiometer for fan-speed and replace the original 4PST rotary switch, but then I got obsessed by the idea of having the 3 levels of speed \u003cstrong\u003einstead be 3 ranges of noise volume\u003c/strong\u003e, and using a tiny PDM microphone to listen to the noise level (or vibration sensor - I have 3 different stiffnesses).\u003c/p\u003e\n\n\u003cp\u003eI think I forgot about the lack of mic's in my collection, and lack of pins spare if I use a QT-PY board, but in theory the idea stretched to having a second control for fan speed (analog input or some time-of-flight gesture sensor).\u003c/p\u003e\n\n\u003cp\u003eIt didn't really matter to me about fanspeed so much as the key control for speed would be the online Adafruit IO Dashboard and the air quality sensor data which would modify the fan speed all the time. \u003c/p\u003e\n\n\u003cp\u003eFor now (and probably when ruminating before) I think it's best to forget manual fan speed control and instead set a desired volume range with the old speed dial (4PST switch), and use that as a multiplier to the air-quality data value, so the fan speed still varies in dirty/clean air while allowing the user to have near silence when required and cleaner air quicker when more tolerant of noise.\u003c/p\u003e\n","metadata":{"markdown":"### Decisions, decisions... January 2024\n\nI need to have something where the original knob / speed-dial went. I've managed to source the original 4-Pole Single-Throw (4PST) rotary switch, which gives 4 positions (off \u0026amp; speeds 1-3), and I've also got a rotary potentiometer to allow full analog selection of the fan speed value. I need to pick one :shrug: or drill another hole for the second one and use both. \n\nThe original thought was use the potentiometer for fan-speed and replace the original 4PST rotary switch, but then I got obsessed by the idea of having the 3 levels of speed **instead be 3 ranges of noise volume**, and using a tiny PDM microphone to listen to the noise level (or vibration sensor - I have 3 different stiffnesses).\n\nI think I forgot about the lack of mic's in my collection, and lack of pins spare if I use a QT-PY board, but in theory the idea stretched to having a second control for fan speed (analog input or some time-of-flight gesture sensor).\n\nIt didn't really matter to me about fanspeed so much as the key control for speed would be the online Adafruit IO Dashboard and the air quality sensor data which would modify the fan speed all the time. \n\nFor now (and probably when ruminating before) I think it's best to forget manual fan speed control and instead set a desired volume range with the old speed dial (4PST switch), and use that as a multiplier to the air-quality data value, so the fan speed still varies in dirty/clean air while allowing the user to have near silence when required and cleaner air quicker when more tolerant of noise."}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/811/original/20240218_190237.jpeg?1712663350","metadata":{"caption":"First thought, a prototype PCB (perfboard), testing if the cable will comfortably stretch (barely)"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eUpdate - April 2024\u003c/h2\u003e\n\u003cp\u003eI've repurposed the DotStars after hearing from \u003ca href=\"https://kattni.com/about\" target=\"_blank\"\u003eKattni\u003c/a\u003e that they may be the right kind of light frequencies for plants (with the addition of some cool/normal whites too), so a NeoPixel string has replaced the original DotStar talk.\u003c/p\u003e\n\u003cp\u003ePretty much feature complete, works well enough to never touch again (been using CircuitPython Web Workflow for updates), but I'd like to add some gentle pulsating with colour based on air quality + temp etc (there's an I2C sensor inside too), along with the status neopixel and main string indicating online or physical dial changes and wifi connecting etc.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eParts Used\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003e1. \u003cspan style=\"text-decoration: underline;\"\u003eAn ItsyBitsy ESP32 board (either PCB antenna or external w.Fl version + aerial):\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5890","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5445","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eOr\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5889","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003e2. \u003cspan style=\"text-decoration: underline;\"\u003eA larger Prototype PCB (8cm x 3cm version - 24x10 2.54mm holes) and a smaller version (8x10 2.54mm holes):\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4784","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n        \u003cp\u003e3. \u003cspan style=\"text-decoration: underline;\"\u003eA four pole single throw (4PST) rotary switch:\u003c/span\u003e\u003cbr\u003e\u0026nbsp;\u0026nbsp;\u003cem\u003eGet the original one carefully unsoldered, or buy a replacement from LCSC or mouser(3x price), etc, but the stalk / knob may need cutting down (it's got a 15mm shaft instead of 10mm approx)\u003c/em\u003e\u003c/p\u003e\n      \n\n\n\n","metadata":{}},{"element_type":"parts","content":"\n  \u003cdiv class=\"parts-details\"\u003e\n    \u003cdiv\u003e\n      \u003cspan class=\"parts-quantity\"\u003e1\u003c/span\u003e\u003cspan\u003e x \u003c/span\u003e\n        \u003ca href=\"https://www.lcsc.com/product-detail/Rotary-Switches_ALPSALPINE-SRBV141201_C470372.html\" class=\"parts-name\" target=\"_blank\"\u003eALPSALPINE SRBV141201\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003e4PST Non Shorting 30° 4 1 300mA 16V Plugin Rotary Switches ROHS\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n  \u003cdiv class=\"parts-action\"\u003e\n  \u003cdiv\u003e\n      \u003ca href=\"https://www.lcsc.com/product-detail/Rotary-Switches_ALPSALPINE-SRBV141201_C470372.html\" class=\"parts-url btn-secondary\" target=\"_blank\"\u003eBuy Now\u003c/a\u003e\n\n  \u003c/div\u003e\n\u003c/div\u003e\n\n  \u003cdiv class=\"clearfix\"\u003e\u003c/div\u003e\n","metadata":{"name":"ALPSALPINE SRBV141201","url":"https://www.lcsc.com/product-detail/Rotary-Switches_ALPSALPINE-SRBV141201_C470372.html","description":"4PST Non Shorting 30° 4 1 300mA 16V Plugin Rotary Switches ROHS","quantity":"1"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n        \u003cp\u003e4. DC-DC converter (buck) to convert 24V to 5V - I used the MP1584EN\u003cspan style=\"text-decoration: underline;\"\u003e.\u003c/span\u003e\u003c/p\u003e\n\u003cp style=\"padding-left: 40px;\"\u003e\u003cem\u003ePurchase link on AliExpress.com: \u003ca href=\"https://www.aliexpress.com/item/1005005758555624.html\" target=\"_blank\"\u003ehttps://www.aliexpress.com/item/1005005758555624.htm\u003c/a\u003el\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e5.\u0026nbsp;\u003cspan style=\"text-decoration: underline;\"\u003eLots of screw terminals and JST sockets and female header sockets, etc, or just used standard dupont jumper cables / wire directly to prototype PCB.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eRelies on an air quality sensor pushing the air quality data to an Adafruit IO feed!\u003c/h2\u003e\n\u003cp\u003e\u003cem\u003e\u003cspan style=\"text-decoration: underline;\"\u003e\u003cstrong\u003ee.g.\u003c/strong\u003e\u003c/span\u003e\u003c/em\u003e\u0026nbsp; \u0026nbsp;Here are two devices, one micropython left and one circuitpython right, but you could have a no-code adafruit IO wippersnapper firmware running on your device instead...\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/820/original/IMG_20240410_020805_753_%281%29.jpg?1713035534","metadata":{"caption":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eMain Circuitry Photo Details:\u003c/h1\u003e\n      \n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/812/original/IMG_20240325_112157_848.jpeg?1712663807","metadata":{"caption":"The board can be easily pulled off of the rotary switch for maintenance, and the itsy removed too. Eagle eyed readers will spot a light spot / whiter point in the case (near the protruding strut on internal side) and the glue stick stubby tower between the internal white plastic struts."}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/813/original/IMG_20240325_112145_669.jpeg?1712664166","metadata":{"caption":""}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/815/original/IMG_20240325_110332_175.jpeg?1712664213","metadata":{"caption":""}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/816/original/IMG_20240325_112048_789.jpeg?1712664239","metadata":{"caption":""}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/818/original/IMG_20240325_112035_736.jpeg?1712664273","metadata":{"caption":""}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/817/original/IMG_20240325_112101_750.jpeg?1712664256","metadata":{"caption":""}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/819/original/IMG_20240325_112106_678.jpeg?1712664328","metadata":{"caption":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n        \u003cp\u003e\u003cspan style=\"text-decoration: underline;\"\u003e\u003cstrong\u003ePoints to note:\u003c/strong\u003e\u003c/span\u003e\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eWrapped middle of MP1584EN DC converter in Kapton tape to avoid the risk of shorting any exposed via's and affecting the reliability of the power supply, before soldering to the smaller prototype board.\u003cbr\u003e\u0026nbsp;\u003c/li\u003e\n\u003cli\u003eUsed shallow / low-profile SMT through-hole sockets (double row - 2x20pin connectors chopped down in length), partially as a test of if they trimmed okay, but mainly due to being a bit less deep than the female side of the short header kit from Adafruit and similar at 6.5mm female 3.5mm male plastic sections.\u003cbr\u003e\u0026nbsp;\u003c/li\u003e\n\u003cli\u003eI \u003cstrong\u003ecreated a light pipe\u003c/strong\u003e for the onboard NeoPixel\u0026nbsp;\u003cstrong\u003efrom a\u003c/strong\u003e \u003cstrong\u003eGlue stick!\u003c/strong\u003e (And it worked so well...)\n\u003col\u003e\n\u003cli\u003e\u003cspan\u003eI initially softened the middle and bent slightly in S-shape with a hot air gun.\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003eNext wetted one end / softly melted with hot air gun (until clear and glistening), then gently placed into the external case's old LED light hole (originally for indicating filter change).\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003eRemoved again and checked, not fully formed but hole shape achieved, will remelt once and repeat for better projection of material through hole.\u0026nbsp;\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003eThen remove again ready for device side. Prep by inserting StemmaQT cable into ItsyBitsy ESP32, wrap cable and socket in Kapton (heat resistant) tape.\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003eTrim unmodified end of glue stick to approximated fit between StemmaQT port, the esp32 module steel can, and the pin area, leaving a clear section sat on the face of the NeoPixel.\u003cbr\u003e\u003cem\u003e\u0026nbsp; I removed about a third of the glue stick in a gentle angled snip, then trimmed a little bit more from the bottom \"corners\" of the glue stick to fit the space better.\u003cbr\u003e\u003c/em\u003e\n\u003c/li\u003e\n\u003cli\u003eFinally wet / softly melt that end of the glue stick with heat gun (was probably about 160c at various points), and gently force down onto neopixel in the final position and hold for at least ten seconds, then blow on it and gently remove.\u003cbr\u003e\u003cem\u003e\u0026nbsp; I was able to carefully insert the cold (formed end for the hole) into the light hole in the Ikea fan case, and then with the other end of the glue stick still wet do a final placement of the Itsy into the gluestick and held it firmly in place for about twenty seconds.\u003cbr\u003e\u003cbr\u003e\u003c/em\u003eIt's still removable afterwards, but has a nice light transmission, and the glue stick stays in place due to having a lug in the light hole of the external case.\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cbr\u003eI think \u003cem\u003esecretly\u003c/em\u003e this was the whole aim of the project, to use glue sticks as light pipes\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;🌈🔍💡 = 🧠 +⏳(+ 💷)\u003cbr\u003e😇\u003c/p\u003e\n      \n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/821/original/IMG_20240409_215043_246.jpg?1713036010","metadata":{"caption":"NeoPixel RGB LED shining through the glue stick \"light-pipe\" at the top of the unit, currently showing a green status"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eFritzing Diagram created to almost reflect reality\u003cbr\u003e(screw-terminals/JSTs on reverse of boards):\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/798/original/Ikea_FornuftigV2_PCB_bb.png?1712659576","metadata":{"caption":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cul\u003e\n\u003cli\u003eTop board is ItsyBitsy ESP32 carrier, with sockets for the Itsy plus a 4 pole single throw rotary switch (matches the original in IKEA Forunuftig except with longer stalk / shaft). Also has screw terminals for PCB-to-PCB connection (5V-in, ground, Fan PWM out, Tachometer IN), along with NeoPixel string terminals (5v, Sig, Gnd).\u003cbr\u003e\u0026nbsp;\u003c/li\u003e\n\u003cli\u003eLower board is 24V to 5V converter (MP1584EN adjustable dc converter set to 4.99v), along with JST sockets for the original 24V power supply (2pin) and Fan (4pin).\u003cbr\u003e\u0026nbsp;Originally I assumed I'd need additional mosfet to drive the fan, so had incorporated two more connections on this board to accommodate sending the PWM signal from the ItsyBitsy ESP32 to an additional Stemma Mosfet Driver board (Stemma is JST PH 3pin - or 4pin for I2C) before outputting to the fan (You can see in the photos additional 2pin and 3pin connectors)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003e\n\u003cspan style=\"text-decoration: underline;\"\u003eSemi-finished code:\u003c/span\u003e - Functionally capable but no reactive light use, rainbow:\u003cbr\u003e[Reproduced from\u0026nbsp;\u003ca href=\"https://github.com/tyeth/Ikea_ItsyBitsyEsp32_Air_Purifier/\"\u003ehttps://github.com/tyeth/Ikea_ItsyBitsyEsp32_Air_Purifier/\u003c/a\u003e ]\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003e\u003cstrong\u003eReadme.md\u003c/strong\u003e\u003c/h1\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"markdown","content":"\u003ch1\u003eItsyBitsy ESP32 IKEA Fornuftig Air Cleaner v2 Noise Adjustable\u003c/h1\u003e\n\n\u003cp\u003eThis project integrates air quality data from Adafruit IO (using the Good-enough Air Quality project) with a custom air quality monitoring and adjustment system developed using CircuitPython on a microcontroller platform. It aims to provide a real-time air quality monitoring and adjustment solution, enhancing environmental conditions based on air quality data, while respecting desired noise levels.\u003c/p\u003e\n\n\u003cp\u003eUses asyncio to have a multiple tasks situation, with one doing the rainbow lights, one task fetching from Adafruit IO, one monitoring the fan speed (tachometer), and even a dummy spare task for you to easily change to incorporate some extra functionality.\u003c/p\u003e\n\n\u003cp\u003eSee matching write-up / photos / note on Adafruit-Playground:\u003c/p\u003e\n\n\u003cp\u003e\u003ca href=\"https://adafruit-playground.com/u/tyeth/pages/ikea-fornufig-air-purifier-v2-custom-fan-speed-controller-blinkenlights\"\u003ehttps://adafruit-playground.com/u/tyeth/pages/ikea-fornufig-air-purifier-v2-custom-fan-speed-controller-blinkenlights\u003c/a\u003e\u003c/p\u003e\n\n\u003ch2\u003eInstallation\u003c/h2\u003e\n\n\u003ch3\u003ePrerequisites\u003c/h3\u003e\n\n\u003cul\u003e\n\u003cli\u003eCircuitPython compatible microcontroller (e.g., Adafruit ItsyBitsy ESP32)\u003c/li\u003e\n\u003cli\u003eRequired libraries from the \u003ca href=\"https://circuitpython.org/libraries\"\u003eCircuitPython Library Bundle\u003c/a\u003e:\n\n\u003cul\u003e\n\u003cli\u003e'adafruit_connection_manager'\u003c/li\u003e\n\u003cli\u003e'adafruit_io'\u003c/li\u003e\n\u003cli\u003e'adafruit_minimqtt'\u003c/li\u003e\n\u003cli\u003e'adafruit_pixelbuf'\u003c/li\u003e\n\u003cli\u003e'adafruit_requests'\u003c/li\u003e\n\u003cli\u003e'adafruit_ticks'\u003c/li\u003e\n\u003cli\u003e'asyncio'\u003c/li\u003e\n\u003cli\u003e'neopixel'\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eExample dependency install with circup using web workflow:\u003c/p\u003e\n\u003ccode class=\"shell\"\u003e\u003cpre\u003eC:\\Users\\tyeth\u0026gt;circup --host 192.168.0.232 --password password install --auto\nFound device at http://:password@192.168.0.232, running CircuitPython 9.0.2.\nDownloading latest bundles for adafruit/Adafruit_CircuitPython_Bundle (20240402).\npy:\nExtracting:  [####################################]  100%\n8.x-mpy:\nExtracting:  [####################################]  100%\n9.x-mpy:\nExtracting:  [####################################]  100%\n\nOK\n\nAuto file: code.py\nAuto file path: C:\\Users\\tyeth\\AppData\\Local\\adafruit\\circup\\code.tmp.py\nSearching for dependencies for: ['adafruit_io', 'adafruit_requests', 'asyncio', 'neopixel']\nReady to install: ['adafruit_connection_manager', 'adafruit_io', 'adafruit_minimqtt', 'adafruit_pixelbuf', 'adafruit_requests', 'adafruit_ticks', 'asyncio', 'neopixel']\n\nInstalled 'adafruit_connection_manager'.\nInstalled 'adafruit_io'.\nInstalled 'adafruit_minimqtt'.\nInstalled 'adafruit_pixelbuf'.\nInstalled 'adafruit_requests'.\nInstalled 'adafruit_ticks'.\nInstalled 'asyncio'.\nInstalled 'neopixel'.\n\u003c/pre\u003e\u003c/code\u003e\n\u003ch3\u003eSetup\u003c/h3\u003e\n\n\u003col\u003e\n\u003cli\u003eEnsure your microcontroller is running the latest version of CircuitPython.\u003c/li\u003e\n\u003cli\u003eClone this repository to your local machine.\u003c/li\u003e\n\u003cli\u003eCopy \u003ccode class=\"inline\"\u003ecode.py\u003c/code\u003e and \u003ccode class=\"inline\"\u003esettings.toml\u003c/code\u003e to the root of your microcontroller's filesystem.\u003c/li\u003e\n\u003cli\u003eInstall the necessary CircuitPython libraries by copying them from the Library Bundle to the \u003ccode class=\"inline\"\u003elib\u003c/code\u003e folder on your microcontroller,\nor using \u003ccode class=\"inline\"\u003ecircup\u003c/code\u003e the circuitpython package manager\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2\u003eUsage\u003c/h2\u003e\n\n\u003cp\u003eAfter installing the project files and necessary libraries on your microcontroller, reset the device to start the program. The device will:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eConnect to WiFi using credentials specified in \u003ccode class=\"inline\"\u003esettings.toml\u003c/code\u003e (ensure this file is updated with your network information).\u003c/li\u003e\n\u003cli\u003eFetch air quality data from the Good-enough Air Quality project or another specified source and scale fan speed accordingly.\u003c/li\u003e\n\u003cli\u003eUse onboard sensors and outputs (LEDs etc.) to indicate air quality status and adjustments being made.\u003c/li\u003e\n\u003cli\u003eListen to Control Dial for requested Maximum Noise Level, and scale fan speed accordingly.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eMonitor serial output for logs and diagnostics.\u003c/p\u003e\n\n\u003ch3\u003eConfiguration\u003c/h3\u003e\n\n\u003cp\u003eEdit \u003ccode class=\"inline\"\u003esettings.toml\u003c/code\u003e to include your settings (like wifi details). Below is a list of variables you need to set:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eADAFRUIT_IO_USERNAME\u003c/code\u003e - Your Adafruit IO username.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eADAFRUIT_IO_KEY\u003c/code\u003e - Your Adafruit IO key.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eSTATUS_NEOPIXEL_BRIGHTNESS\u003c/code\u003e - Brightness of the status NeoPixel (range 0.0 to 1.0).\u003c/li\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eFAN_SPEED_FEEDNAME\u003c/code\u003e - Feed name for fan speed in Adafruit IO.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eAIR_QUALITY_FEEDNAME\u003c/code\u003e - Feed name for air quality in Adafruit IO.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode class=\"inline\"\u003eNOISE_LEVEL_1_MAX_FAN_FREQUENCY\u003c/code\u003e, \u003ccode class=\"inline\"\u003eNOISE_LEVEL_2_MAX_FAN_FREQUENCY\u003c/code\u003e, \u003ccode class=\"inline\"\u003eNOISE_LEVEL_3_MAX_FAN_FREQUENCY\u003c/code\u003e - Maximum fan frequencies for noise levels 1, 2, and 3.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eEnsure you replace placeholders (e.g., \u003ccode class=\"inline\"\u003eYOUR_USERNAME_HERE\u003c/code\u003e) with actual values.\u003c/p\u003e\n\n\u003ch2\u003eDependencies\u003c/h2\u003e\n\n\u003cp\u003eThis project depends on several external libraries and services:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://circuitpython.org/\"\u003eCircuitPython\u003c/a\u003e for programming the microcontroller.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://io.adafruit.com/\"\u003eAdafruit IO\u003c/a\u003e for online data logging and retrieval.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://github.com/good-enough-technology/Good-Enough_Air-Quality-Device_CO2-SCD4x_PM-SEN5x_CircuitPython\"\u003eGood-enough Air Quality project\u003c/a\u003e or another air quality data source.\u003c/li\u003e\n\u003cli\u003eVarious CircuitPython libraries as mentioned in the prerequisites.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2\u003eLicense\u003c/h2\u003e\n\n\u003cp\u003eThis project is currently unlicensed\u003c/p\u003e\n","metadata":{"markdown":"# ItsyBitsy ESP32 IKEA Fornuftig Air Cleaner v2 Noise Adjustable\n\nThis project integrates air quality data from Adafruit IO (using the Good-enough Air Quality project) with a custom air quality monitoring and adjustment system developed using CircuitPython on a microcontroller platform. It aims to provide a real-time air quality monitoring and adjustment solution, enhancing environmental conditions based on air quality data, while respecting desired noise levels.\n\nUses asyncio to have a multiple tasks situation, with one doing the rainbow lights, one task fetching from Adafruit IO, one monitoring the fan speed (tachometer), and even a dummy spare task for you to easily change to incorporate some extra functionality.\n\n\nSee matching write-up / photos / note on Adafruit-Playground:\n\n[https://adafruit-playground.com/u/tyeth/pages/ikea-fornufig-air-purifier-v2-custom-fan-speed-controller-blinkenlights](https://adafruit-playground.com/u/tyeth/pages/ikea-fornufig-air-purifier-v2-custom-fan-speed-controller-blinkenlights)\n\n## Installation\n\n### Prerequisites\n\n- CircuitPython compatible microcontroller (e.g., Adafruit ItsyBitsy ESP32)\n- Required libraries from the [CircuitPython Library Bundle](https://circuitpython.org/libraries):\n  - 'adafruit\\_connection_manager'\n  - 'adafruit_io'\n  - 'adafruit_minimqtt'\n  - 'adafruit_pixelbuf'\n  - 'adafruit_requests'\n  - 'adafruit_ticks'\n  - 'asyncio'\n  - 'neopixel'\n\nExample dependency install with circup using web workflow:\n```shell\nC:\\Users\\tyeth\u0026gt;circup --host 192.168.0.232 --password password install --auto\nFound device at http://:password@192.168.0.232, running CircuitPython 9.0.2.\nDownloading latest bundles for adafruit/Adafruit_CircuitPython_Bundle (20240402).\npy:\nExtracting:  [####################################]  100%\n8.x-mpy:\nExtracting:  [####################################]  100%\n9.x-mpy:\nExtracting:  [####################################]  100%\n\nOK\n\nAuto file: code.py\nAuto file path: C:\\Users\\tyeth\\AppData\\Local\\adafruit\\circup\\code.tmp.py\nSearching for dependencies for: ['adafruit_io', 'adafruit_requests', 'asyncio', 'neopixel']\nReady to install: ['adafruit_connection_manager', 'adafruit_io', 'adafruit_minimqtt', 'adafruit_pixelbuf', 'adafruit_requests', 'adafruit_ticks', 'asyncio', 'neopixel']\n\nInstalled 'adafruit_connection_manager'.\nInstalled 'adafruit_io'.\nInstalled 'adafruit_minimqtt'.\nInstalled 'adafruit_pixelbuf'.\nInstalled 'adafruit_requests'.\nInstalled 'adafruit_ticks'.\nInstalled 'asyncio'.\nInstalled 'neopixel'.\n```\n\n### Setup\n\n1. Ensure your microcontroller is running the latest version of CircuitPython.\n2. Clone this repository to your local machine.\n3. Copy `code.py` and `settings.toml` to the root of your microcontroller's filesystem.\n4. Install the necessary CircuitPython libraries by copying them from the Library Bundle to the `lib` folder on your microcontroller,\nor using `circup` the circuitpython package manager\n\n## Usage\n\nAfter installing the project files and necessary libraries on your microcontroller, reset the device to start the program. The device will:\n\n- Connect to WiFi using credentials specified in `settings.toml` (ensure this file is updated with your network information).\n- Fetch air quality data from the Good-enough Air Quality project or another specified source and scale fan speed accordingly.\n- Use onboard sensors and outputs (LEDs etc.) to indicate air quality status and adjustments being made.\n- Listen to Control Dial for requested Maximum Noise Level, and scale fan speed accordingly.\n\nMonitor serial output for logs and diagnostics.\n\n### Configuration\n\nEdit `settings.toml` to include your settings (like wifi details). Below is a list of variables you need to set:\n\n- `ADAFRUIT_IO_USERNAME` - Your Adafruit IO username.\n- `ADAFRUIT_IO_KEY` - Your Adafruit IO key.\n- `STATUS_NEOPIXEL_BRIGHTNESS` - Brightness of the status NeoPixel (range 0.0 to 1.0).\n- `FAN_SPEED_FEEDNAME` - Feed name for fan speed in Adafruit IO.\n- `AIR_QUALITY_FEEDNAME` - Feed name for air quality in Adafruit IO.\n- `NOISE_LEVEL_1_MAX_FAN_FREQUENCY`, `NOISE_LEVEL_2_MAX_FAN_FREQUENCY`, `NOISE_LEVEL_3_MAX_FAN_FREQUENCY` - Maximum fan frequencies for noise levels 1, 2, and 3.\n\nEnsure you replace placeholders (e.g., `YOUR_USERNAME_HERE`) with actual values.\n\n## Dependencies\n\nThis project depends on several external libraries and services:\n\n- [CircuitPython](https://circuitpython.org/) for programming the microcontroller.\n- [Adafruit IO](https://io.adafruit.com/) for online data logging and retrieval.\n- [Good-enough Air Quality project](https://github.com/good-enough-technology/Good-Enough_Air-Quality-Device_CO2-SCD4x_PM-SEN5x_CircuitPython) or another air quality data source.\n- Various CircuitPython libraries as mentioned in the prerequisites.\n\n## License\n\nThis project is currently unlicensed"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003e\n\u003cstrong\u003esettings.toml\u003c/strong\u003e (most values are optional)\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/tyeth/Ikea_ItsyBitsyEsp32_Air_Purifier/blob/main/settings.toml"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003e\u003cstrong\u003ecode.py\u003c/strong\u003e\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/tyeth/Ikea_ItsyBitsyEsp32_Air_Purifier/blob/main/code.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch4\u003eIf you made it this far you deserve a video:\u003c/h4\u003e\n\u003cp\u003eThe status light on top of the unit is on the lowest brightness for the onboard NeoPixel at 0.08 brightness.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://youtube.com/shorts/xjA0JAfIvJE"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eWhat about the no-code Blockly version? It's coming soon, but the maths functions I need are a few weeks away from being back in focus, then released.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n","metadata":{}}]