[{"element_type":"markdown","content":"\u003ch2\u003eIntroduction\u003c/h2\u003e\n\n\u003cp\u003eWe have a 1960's era aluminum Christmas tree. For the time that we've had it we've relied on newer and slightly less dangerous color wheels, then stage lighting. When we moved we didn't bring any of the lighting with us.\u003c/p\u003e\n\n\u003cp\u003eI decided to string the poles of the tree with LEDs.\u003c/p\u003e\n\n\u003cp\u003eThe prior year I made a star topper which used a Bluefruit for lighting. This year I added 24 LEDs for the star that plug into the highest string on the poles.\u003c/p\u003e\n\n\u003ch2\u003eDesign\u003c/h2\u003e\n\n\u003cp\u003eThe current design is written in CircuitPython. For communication it relies on MQTT and Node-Red. \u003c/p\u003e\n\n\u003cp\u003eEverything worked great, however, after I worked on a different LED project that used WLED, I think I'll convert this project to WLED. I'm not going to delete this code base, I think it has some interesting implementation features and is worth preserving.\u003c/p\u003e\n\n\u003cp\u003eInfrastructure-wise with either implmentation you will need:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003eMQTT - you can use \u003ca href=\"https://io.adafruit.com/\"\u003eAdafruitIO\u003c/a\u003e or build your own. In my implementation I set up a broker on a RaspberryPi 4 Model B running Debian Bookworm and \u003ca href=\"https://mosquitto.org/\"\u003eMosquitto\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eNode-Red - \u003ca href=\"https://adafruit-playground.com/u/ntynen/pages/home-hub-project-with-node-red-dashboard\"\u003emy Node-Red journey\u003c/a\u003e is chronicled here.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2\u003eParts\u003c/h2\u003e\n","metadata":{"markdown":"## Introduction\nWe have a 1960's era aluminum Christmas tree. For the time that we've had it we've relied on newer and slightly less dangerous color wheels, then stage lighting. When we moved we didn't bring any of the lighting with us.\n\nI decided to string the poles of the tree with LEDs.\n\nThe prior year I made a star topper which used a Bluefruit for lighting. This year I added 24 LEDs for the star that plug into the highest string on the poles.\n\n## Design\nThe current design is written in CircuitPython. For communication it relies on MQTT and Node-Red. \n\nEverything worked great, however, after I worked on a different LED project that used WLED, I think I'll convert this project to WLED. I'm not going to delete this code base, I think it has some interesting implementation features and is worth preserving.\n\nInfrastructure-wise with either implmentation you will need:\n\n* MQTT - you can use [AdafruitIO](https://io.adafruit.com/) or build your own. In my implementation I set up a broker on a RaspberryPi 4 Model B running Debian Bookworm and [Mosquitto](https://mosquitto.org/).\n* Node-Red - [my Node-Red journey](https://adafruit-playground.com/u/ntynen/pages/home-hub-project-with-node-red-dashboard) is chronicled here.\n\n## Parts"}},{"element_type":"product","content":"https://www.adafruit.com/product/5400","metadata":{"name":"Adafruit Feather","url":"https://www.adafruit.com/product/5400","description":"ESP32 v2","quantity":"1","featured":false}},{"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.amazon.com/dp/B09PBTSYFY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11\" class=\"parts-name\" target=\"_blank\"\u003eLED Light Strip\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003eWS2812b Individually Addressable led Strip\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.amazon.com/dp/B09PBTSYFY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11\" class=\"parts-url btn-primary\" 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":"LED Light Strip","url":"https://www.amazon.com/dp/B09PBTSYFY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11","description":"WS2812b Individually Addressable led Strip","quantity":"1"}},{"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.amazon.com/dp/B01DC0KIT2?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11\" class=\"parts-name\" target=\"_blank\"\u003e3-Pin Connectors Male/Female\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003eJST SM 3 Pin Connectors\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.amazon.com/dp/B01DC0KIT2?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11\" class=\"parts-url btn-primary\" 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":"3-Pin Connectors Male/Female","url":"https://www.amazon.com/dp/B01DC0KIT2?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_11","description":"JST SM 3 Pin Connectors","quantity":"1"}},{"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.amazon.com/dp/B09PR418WZ?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_7\" class=\"parts-name\" target=\"_blank\"\u003e3-Pin Connectors Clear\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003e3 Pin 10mm Solderless LED Light Strip Connectors\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.amazon.com/dp/B09PR418WZ?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_7\" class=\"parts-url btn-primary\" 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":"3-Pin Connectors Clear","url":"https://www.amazon.com/dp/B09PR418WZ?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_7","description":"3 Pin 10mm Solderless LED Light Strip Connectors","quantity":"1"}},{"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.amazon.com/dp/B0852HL336?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_3\" class=\"parts-name\" target=\"_blank\"\u003ePower Supply\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003e5V 10A Power Supply Adapter\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.amazon.com/dp/B0852HL336?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_3\" class=\"parts-url btn-primary\" 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":"Power Supply","url":"https://www.amazon.com/dp/B0852HL336?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_3","description":"5V 10A Power Supply Adapter","quantity":"1"}},{"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.amazon.com/dp/B07G2GLKMP?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1\" class=\"parts-name\" target=\"_blank\"\u003eFlexible Stranded Wire\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003e20 AWG\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.amazon.com/dp/B07G2GLKMP?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1\" class=\"parts-url btn-primary\" 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":"Flexible Stranded Wire","url":"https://www.amazon.com/dp/B07G2GLKMP?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1","description":"20 AWG","quantity":"1"}},{"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.amazon.com/dp/B06XCCRPRY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1\" class=\"parts-name\" target=\"_blank\"\u003eUglu Dashes\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003eAdhesive\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.amazon.com/dp/B06XCCRPRY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1\" class=\"parts-url btn-primary\" 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":"Uglu Dashes","url":"https://www.amazon.com/dp/B06XCCRPRY?ref_=ppx_hzsearch_conn_dt_b_fed_asin_title_1","description":"Adhesive","quantity":"1"}},{"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.walmart.com/ip/5-5x2-1mm-Male-Female-DC-Power-Plug-Jack-Connectors-for-LED-Lights-CCTV-Electronics/3916144470\" class=\"parts-name\" target=\"_blank\"\u003eJack Connectors\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003e5.5x2.1mm Male / Female DC Power Plug / Jack Connectors\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.walmart.com/ip/5-5x2-1mm-Male-Female-DC-Power-Plug-Jack-Connectors-for-LED-Lights-CCTV-Electronics/3916144470\" class=\"parts-url btn-primary\" 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":"Jack Connectors","url":"https://www.walmart.com/ip/5-5x2-1mm-Male-Female-DC-Power-Plug-Jack-Connectors-for-LED-Lights-CCTV-Electronics/3916144470","description":"5.5x2.1mm Male / Female DC Power Plug / Jack Connectors","quantity":"1"}},{"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.amazon.com/dp/B0BRTJQGS6\" class=\"parts-name\" target=\"_blank\"\u003eBreadboard Jumper Wires (optional)\u003c/a\u003e\n      \u003cdiv class=\"parts-description\"\u003eJumper wires\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.amazon.com/dp/B0BRTJQGS6\" class=\"parts-url btn-primary\" 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":"Breadboard Jumper Wires (optional)","url":"https://www.amazon.com/dp/B0BRTJQGS6","description":"Jumper wires","quantity":"1"}},{"element_type":"markdown","content":"\u003ch2\u003eCode\u003c/h2\u003e\n\n\u003ch5\u003eTree \u0026amp; Star\u003c/h5\u003e\n\n\u003cp\u003e\u003ca href=\"https://github.com/niccit/aluminum_tree_pole_lights\"\u003eThe code\u003c/a\u003e can be found on Github\u003c/p\u003e\n\n\u003cp\u003eAs I was coding this project, I found myself thinking I was going to be reusing a lot of it. So I repurposed an \u003ca href=\"https://github.com/niccit/circuitpy_helpers\"\u003eold project\u003c/a\u003e and replaced what was there with new helper classes. \u003c/p\u003e\n\n\u003cp\u003eI did run into an issue where I could not get the LED Animation library to play nicely with MQTT. I tried a few things, including asyncio, and ended up posting on the forums. mikeysklar came to the rescue and you'll see his contribution in the code. \u003c/p\u003e\n\n\u003cp\u003eThe tree has 196 LEDs and the star has 24.\u003c/p\u003e\n\u003ccode class=\"\"\u003e\u003cpre\u003edata = {\n    'tree_animations': ['multi_chase']\n    ,'star_animations': ['rainbow_sparkle']\n    ,'num_pixels' : 220\n    ,'tree_pixel_subset': [0, 195]\n    ,'star_pixel_subset': [196, 24]\n    ...\n }\n\u003c/pre\u003e\u003c/code\u003e\n\u003ch4\u003eLibraries Needed\u003c/h4\u003e\n\u003ccode class=\"\"\u003e\u003cpre\u003eimport json\nimport board\nimport time\nimport os\nimport neopixel\nimport adafruit_logging\nimport wifi\nimport supervisor\nimport adafruit_connection_manager\nimport adafruit_minimqtt.adafruit_minimqtt\nfrom adafruit_led_animation.group import AnimationGroup\nfrom adafruit_minimqtt.adafruit_minimqtt import MMQTTException\nfrom adafruit_led_animation.sequence import AnimationSequence\nfrom adafruit_led_animation.helper import PixelSubset\nfrom circuitpy_helpers.led_animations import animationBuilder\nfrom circuitpy_helpers.led_animations import controlLights\nfrom circuitpy_helpers.led_animations import updateAnimationData\nfrom circuitpy_helpers.file_helpers import updateFiles\nfrom circuitpy_helpers.calendar_time_helpers import timeHelper\nfrom circuitpy_helpers.network_helpers import wanChecker\n\u003c/pre\u003e\u003c/code\u003e\n\u003ch4\u003eFeatured Highlights\u003c/h4\u003e\n\n\u003cp\u003eThe tree subscribes to the following MQTT feeds:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003etree.lights - listens for events from Node-Red to update animation, start time, stop time\u003c/li\u003e\n\u003cli\u003ehome.time - listens for events from home hub in order to know when to stop or start the lights\u003c/li\u003e\n\u003cli\u003ehome.sunset - listens for events from home hub in order to know current sunset, uses this for start time\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eIn order to take events from tree.lights and actually change the running animation and colors, I needed to be able to do a couple of things:\u003c/p\u003e\n\n\u003col\u003e\n\u003cli\u003eHave a list of supported animations - this is done via the animations.json file\u003c/li\u003e\n\u003cli\u003eBe able to override the default values for animations\u003c/li\u003e\n\u003cli\u003eBe able to on-the-fly update the data file to implement the new animation/colors choice\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003cp\u003eWhen the code first starts it will check if there are overrides for the chosen animation and do an in-line replacement of those values. It will then check to see what the color selection is. Color choice is specified in the animations.json file and can be:\u003c/p\u003e\n\n\u003cul\u003e\n\u003cli\u003erandom - a random color will be selected\u003c/li\u003e\n\u003cli\u003edata - in the data file, for each animation is an entry for color. A string representation of the color can be provided or a the name of a color_palette.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003eOnce up and running, about every 30 seconds, the animations will pause long enough for the code to query MQTT for any updates. If a new message arrives the code will update the data file with the appropriate information and perform a \u003ccode class=\"inline\"\u003esupervisor.reload()\u003c/code\u003e.\u003c/p\u003e\n\n\u003cp\u003eYou can also change the start and stop times or disable them so that the lights will run continually.\u003c/p\u003e\n\n\u003cp\u003eWhen using start and stop times; when the criteria is met to do either, the code will light sleep until the alarm is met.\u003c/p\u003e\n\n\u003ch5\u003eCase\u003c/h5\u003e\n\n\u003cp\u003eI used \u003ca href=\"https://openscad.org\"\u003eOpenSCAD\u003c/a\u003e and the \u003ca href=\"https://github.com/mrWheel/YAPP_Box\"\u003eYAPP Box\u003c/a\u003e (Yet Another Parametric Project Box Generator) library from mrWheel for the Feather case. This library is well documented and has a lot of features.\u003c/p\u003e\n\n\u003cp\u003eI found a star on Thingiverse years ago and downloaded the SCAD file. I re-mixed it for my own needs. Unfortunatly now I cannot find the Thing anymore. If you recognize the \u003ca href=\"https://github.com/niccit/largechristmastreestar\"\u003ecode\u003c/a\u003e as yours please let me know so I can give you proper credit.\u003c/p\u003e\n","metadata":{"markdown":"## Code\n\n##### Tree \u0026amp; Star\n\n[The code](https://github.com/niccit/aluminum_tree_pole_lights) can be found on Github\n\nAs I was coding this project, I found myself thinking I was going to be reusing a lot of it. So I repurposed an [old project](https://github.com/niccit/circuitpy_helpers) and replaced what was there with new helper classes. \n\nI did run into an issue where I could not get the LED Animation library to play nicely with MQTT. I tried a few things, including asyncio, and ended up posting on the forums. mikeysklar came to the rescue and you'll see his contribution in the code. \n\nThe tree has 196 LEDs and the star has 24.\n```\ndata = {\n    'tree_animations': ['multi_chase']\n    ,'star_animations': ['rainbow_sparkle']\n    ,'num_pixels' : 220\n    ,'tree_pixel_subset': [0, 195]\n    ,'star_pixel_subset': [196, 24]\n    ...\n }\n ```\n\n\n#### Libraries Needed\n```\nimport json\nimport board\nimport time\nimport os\nimport neopixel\nimport adafruit_logging\nimport wifi\nimport supervisor\nimport adafruit_connection_manager\nimport adafruit_minimqtt.adafruit_minimqtt\nfrom adafruit_led_animation.group import AnimationGroup\nfrom adafruit_minimqtt.adafruit_minimqtt import MMQTTException\nfrom adafruit_led_animation.sequence import AnimationSequence\nfrom adafruit_led_animation.helper import PixelSubset\nfrom circuitpy_helpers.led_animations import animationBuilder\nfrom circuitpy_helpers.led_animations import controlLights\nfrom circuitpy_helpers.led_animations import updateAnimationData\nfrom circuitpy_helpers.file_helpers import updateFiles\nfrom circuitpy_helpers.calendar_time_helpers import timeHelper\nfrom circuitpy_helpers.network_helpers import wanChecker\n```\n\n#### Featured Highlights\n\nThe tree subscribes to the following MQTT feeds:\n\n* tree.lights - listens for events from Node-Red to update animation, start time, stop time\n* home.time - listens for events from home hub in order to know when to stop or start the lights\n* home.sunset - listens for events from home hub in order to know current sunset, uses this for start time\n\nIn order to take events from tree.lights and actually change the running animation and colors, I needed to be able to do a couple of things:\n\n1. Have a list of supported animations - this is done via the animations.json file\n1. Be able to override the default values for animations\n1. Be able to on-the-fly update the data file to implement the new animation/colors choice\n\nWhen the code first starts it will check if there are overrides for the chosen animation and do an in-line replacement of those values. It will then check to see what the color selection is. Color choice is specified in the animations.json file and can be:\n\n* random - a random color will be selected\n* data - in the data file, for each animation is an entry for color. A string representation of the color can be provided or a the name of a color_palette.\n\nOnce up and running, about every 30 seconds, the animations will pause long enough for the code to query MQTT for any updates. If a new message arrives the code will update the data file with the appropriate information and perform a `supervisor.reload()`.\n\nYou can also change the start and stop times or disable them so that the lights will run continually.\n\nWhen using start and stop times; when the criteria is met to do either, the code will light sleep until the alarm is met.\n\n##### Case\n\nI used [OpenSCAD](https://openscad.org) and the [YAPP Box](https://github.com/mrWheel/YAPP_Box) (Yet Another Parametric Project Box Generator) library from mrWheel for the Feather case. This library is well documented and has a lot of features.\n\nI found a star on Thingiverse years ago and downloaded the SCAD file. I re-mixed it for my own needs. Unfortunatly now I cannot find the Thing anymore. If you recognize the [code](https://github.com/niccit/largechristmastreestar) as yours please let me know so I can give you proper credit."}},{"element_type":"markdown","content":"\u003ch2\u003eNode-Red\u003c/h2\u003e\n\n\u003cp\u003eThe Node-Red Dashboard allows anyone to interact with the CircuitPython code and control the \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/174/large1024/tree_lights_node_page1.png?1767928377\"\u003etree lights\u003c/a\u003e.\u003c/p\u003e\n\n\u003cp\u003eEach of the button groups, when selected, will send a JSON string along to the function. It looks like this:\u003c/p\u003e\n\u003ccode class=\"\"\u003e\u003cpre\u003e{\n    \"color_search\": \"custom_sparkle_color\",\n    \"new_color\": \"gold\",\n    \"animation_name\": \"custom_sparkle\"\n}\n\u003c/pre\u003e\u003c/code\u003e\n\u003cp\u003eFrom here it will call two functions, the first is to update the color choice and that code looks like this:\u003c/p\u003e\n\u003ccode class=\"\"\u003e\u003cpre\u003evar search_string =  msg.payload.color_search;\nvar new_color = msg.payload.new_color;\n\nvar newMsg = {\n    \"topic\": \"update_color\"\n    ,\"payload\": {\n        \"filename\": \"data.py\"\n        ,\"search_string\": search_string\n        ,\"new_value\": `'${new_color}'`\n    }\n};\n\nreturn newMsg;\n\u003c/pre\u003e\u003c/code\u003e\n\u003cp\u003eIt will then delay for 10 seconds to allow the update to complete and then update the animation. That code looks like this:\u003c/p\u003e\n\u003ccode class=\"\"\u003e\u003cpre\u003evar new_animation = msg.payload.animation_name;\n\nvar animationChg = {\n    \"topic\": \"update animation\"\n    ,\"payload\": {\n        \"filename\": \"data.py\"\n        ,\"search_string\": \"tree_animations\"\n        ,\"new_value\": `'${new_animation}'`\n        }    \n}\nreturn animationChg;\n\u003c/pre\u003e\u003c/code\u003e\n\u003cp\u003eThe CircuitPython code receives these updates via MQTT. The code will not issue a \u003ccode class=\"inline\"\u003esupervisor.reload()\u003c/code\u003e on the color update, only after the animation has been updated.\u003c/p\u003e\n\n\u003cp\u003eI opted to \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/171/large1024/node-red_tree1.png?1767928184\"\u003eimplement\u003c/a\u003e it this way because it makes it easier to add new animation selections.\u003c/p\u003e\n\n\u003cp\u003eThe Star is its own segment of 24 lights. Therefore, it has its own Node-Red page with the same options the tree has.\u003c/p\u003e\n","metadata":{"markdown":"## Node-Red\n\nThe Node-Red Dashboard allows anyone to interact with the CircuitPython code and control the [tree lights](https://cdn-learn.adafruit.com/user_assets/assets/000/002/174/large1024/tree_lights_node_page1.png?1767928377).\n\nEach of the button groups, when selected, will send a JSON string along to the function. It looks like this:\n\n```\n{\n    \"color_search\": \"custom_sparkle_color\",\n    \"new_color\": \"gold\",\n    \"animation_name\": \"custom_sparkle\"\n}\n```\nFrom here it will call two functions, the first is to update the color choice and that code looks like this:\n```\nvar search_string =  msg.payload.color_search;\nvar new_color = msg.payload.new_color;\n\nvar newMsg = {\n    \"topic\": \"update_color\"\n    ,\"payload\": {\n        \"filename\": \"data.py\"\n        ,\"search_string\": search_string\n        ,\"new_value\": `'${new_color}'`\n    }\n};\n\nreturn newMsg;\n```\nIt will then delay for 10 seconds to allow the update to complete and then update the animation. That code looks like this:\n```\nvar new_animation = msg.payload.animation_name;\n\nvar animationChg = {\n    \"topic\": \"update animation\"\n    ,\"payload\": {\n        \"filename\": \"data.py\"\n        ,\"search_string\": \"tree_animations\"\n        ,\"new_value\": `'${new_animation}'`\n        }    \n}\nreturn animationChg;\n```\nThe CircuitPython code receives these updates via MQTT. The code will not issue a `supervisor.reload()` on the color update, only after the animation has been updated.\n\nI opted to [implement](https://cdn-learn.adafruit.com/user_assets/assets/000/002/171/large1024/node-red_tree1.png?1767928184) it this way because it makes it easier to add new animation selections.\n\nThe Star is its own segment of 24 lights. Therefore, it has its own Node-Red page with the same options the tree has."}},{"element_type":"markdown","content":"\u003ch2\u003eProject Construction\u003c/h2\u003e\n\n\u003ch4\u003eTree\u003c/h4\u003e\n\n\u003cp\u003eBecause this tree has holes for the branches and is two separate pieces, I couldn't just wrap the tree with one uninterrupted strand of LEDs.\u003c/p\u003e\n\n\u003cp\u003eMy solution was to cut the LED strip into segments of 7 LEDs and connect them using the clear connectors and stranded wire. This way I could get the lengths I need to wrap the tree without obstructing any of the holes. Also, where the poles \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/158/large1024/tree_pole2.png?1767843650\"\u003esplit\u003c/a\u003e I used the 3 pin male to female connectors to allow unplugging one pole from the other. I used the 3 pin male to female connector to attach the star to the LEDs on the pole.\u003c/p\u003e\n\n\u003cp\u003eIn order to keep the whole string from \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/159/large1024/tree_pole1.png?1767844183\"\u003esagging\u003c/a\u003e, I used Uglu dashes to hold the connectors in place. \u003c/p\u003e\n\n\u003cp\u003eAt the end of the strand, near the base of the tree, you'll need to attach a \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/160/large1024/tree_pole3.png?1767844870\"\u003ejack connector\u003c/a\u003e for the power supply, and another male/female connector to connect to the Feather.\u003c/p\u003e\n\n\u003cp\u003eI soldered 3 individual headers - power, earth, and data - to the board. Then I soldered a \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/161/large1024/assembled_feather2.png?1767845094\"\u003emale/female connector\u003c/a\u003e to female breadboard jumpers to make detaching easier.\u003c/p\u003e\n\n\u003cp\u003e\u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/162/large1024/assembled_feather1.png?1767845725\"\u003eThe finished product\u003c/a\u003e\u003c/p\u003e\n\n\u003ch3\u003e\u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/165/large1024/star1.png?1767846069\"\u003eStar\u003c/a\u003e\u003c/h3\u003e\n\n\u003cp\u003eFor the star I used \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/163/large1024/star2.png?1767845875\"\u003e4 strips of 6 LEDs\u003c/a\u003e and connected them using the clear connectors and stranded wire. One strip is connected to the male/female connector to connect to the tree.\u003c/p\u003e\n\n\u003cp\u003eThe star itself is \u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/164/large1024/star3.png?1767846014\"\u003etwo halves\u003c/a\u003e and is held together, around the top most branch with magnets. A traditional topper would likely damage the branch.\u003c/p\u003e\n\n\u003ch4\u003eFinished Product\u003c/h4\u003e\n\n\u003cp\u003e\u003ca href=\"https://cdn-learn.adafruit.com/user_assets/assets/000/002/166/large1024/assembled_tree-1.png?1767846233\"\u003eThe tree lit up\u003c/a\u003e\u003c/p\u003e\n","metadata":{"markdown":"## Project Construction\n\n#### Tree\n\nBecause this tree has holes for the branches and is two separate pieces, I couldn't just wrap the tree with one uninterrupted strand of LEDs.\n\nMy solution was to cut the LED strip into segments of 7 LEDs and connect them using the clear connectors and stranded wire. This way I could get the lengths I need to wrap the tree without obstructing any of the holes. Also, where the poles [split](https://cdn-learn.adafruit.com/user_assets/assets/000/002/158/large1024/tree_pole2.png?1767843650) I used the 3 pin male to female connectors to allow unplugging one pole from the other. I used the 3 pin male to female connector to attach the star to the LEDs on the pole.\n\nIn order to keep the whole string from [sagging](https://cdn-learn.adafruit.com/user_assets/assets/000/002/159/large1024/tree_pole1.png?1767844183), I used Uglu dashes to hold the connectors in place. \n\nAt the end of the strand, near the base of the tree, you'll need to attach a [jack connector](https://cdn-learn.adafruit.com/user_assets/assets/000/002/160/large1024/tree_pole3.png?1767844870) for the power supply, and another male/female connector to connect to the Feather.\n\nI soldered 3 individual headers - power, earth, and data - to the board. Then I soldered a [male/female connector](https://cdn-learn.adafruit.com/user_assets/assets/000/002/161/large1024/assembled_feather2.png?1767845094) to female breadboard jumpers to make detaching easier.\n\n[The finished product](https://cdn-learn.adafruit.com/user_assets/assets/000/002/162/large1024/assembled_feather1.png?1767845725)\n\n### [Star](https://cdn-learn.adafruit.com/user_assets/assets/000/002/165/large1024/star1.png?1767846069)\n\nFor the star I used [4 strips of 6 LEDs](https://cdn-learn.adafruit.com/user_assets/assets/000/002/163/large1024/star2.png?1767845875) and connected them using the clear connectors and stranded wire. One strip is connected to the male/female connector to connect to the tree.\n\nThe star itself is [two halves](https://cdn-learn.adafruit.com/user_assets/assets/000/002/164/large1024/star3.png?1767846014) and is held together, around the top most branch with magnets. A traditional topper would likely damage the branch.\n\n#### Finished Product\n\n[The tree lit up](https://cdn-learn.adafruit.com/user_assets/assets/000/002/166/large1024/assembled_tree-1.png?1767846233)"}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/166/original/assembled_tree-1.png?1767846233","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/158/original/tree_pole2.png?1767843650","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/159/original/tree_pole1.png?1767844183","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/160/original/tree_pole3.png?1767844870","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/161/original/assembled_feather2.png?1767845094","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/162/original/assembled_feather1.png?1767845725","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/163/original/star2.png?1767845875","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/164/original/star3.png?1767846014","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/165/original/star1.png?1767846069","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/171/original/node-red_tree1.png?1767928184","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/002/174/original/tree_lights_node_page1.png?1767928377","metadata":{}}]