[{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/230/original/TV_Backlight_test.png?1696876107","metadata":{"caption":""}},{"element_type":"text","content":"\n        \u003ch2\u003eOverview\u003c/h2\u003e\n\u003cp\u003eThe TV Backlight illuminates the wall behind the TV display to reduce eye strain. The backlight extends the background of the screen image by watching the color near an edge of the display. To reduce distraction, the color and brightness are integrated over time to avoid sudden changes.\u003c/p\u003e\n\u003cp\u003eThe project's \u003cem\u003e\u003cstrong\u003eCircuitPython \u003c/strong\u003e\u003c/em\u003ecode reads the AS7341 spectrometer sensor's eight visible light channels to determine the backlight target color. Using a Euclidean \"color distance\" comparison, the backlight color is slowly changed to match the target color, within a specified tolerance.\u003c/p\u003e\n\u003cp\u003eThe spectrometer sensor settings are adjusted for relatively low display light levels. The sensor's internal amplifier gain is set to maximum and the integration step and time values are adjusted to maintain a moderately fast conversion rate. Also, rather than just analyzing red, green, and blue components, all eight visible light channels are used to increase the accuracy and resolution of color measurements.\u003c/p\u003e\n\u003cp\u003eIn this configuration, just one of the sensor's channels can reach a count value of near 13k, producing a composite 8-channel resolution that approaches 8x10\u003csup\u003e32\u003c/sup\u003e color combinations, much larger than the 17x10\u003csup\u003e6\u003c/sup\u003e (24-bit) color resolution of the NeoPixel strip. A color count to RGB converter helper reads the three primary color sensor channels, scales the count, and produces an RGB888 (24-bit) color value that's compatible with NeoPixels.\u003c/p\u003e\n\u003cp\u003eTo assist in finding a position near the TV screen for the sensor, the Feather M4's on-board NeoPixel mimics the readings in real-time, albeit at a slightly lower brightness than the illumination strip NeoPixels.\u003c/p\u003e\n\u003ch2\u003eDocuments\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003e\u003c/span\u003eTest video: \u003ca class=\"anchor-1X4H4q anchorUnderlineOnHover-wiZFZ_\" title=\"https://youtu.be/yFqbalF0FGw\n\n(https://youtu.be/yFqbalF0FGw)\" href=\"https://youtu.be/yFqbalF0FGw\" target=\"_blank\"\u003e\u003cspan\u003ehttps://youtu.be/yFqbalF0FGw\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\n\u003ch2\u003eNext Steps\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan\u003eBuild a camouflaged enclosure and vertical mounting wands for the NeoPixel strips.\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003eInvestigate animating the NeoPixel strip color change.\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan\u003eFor home security, enable the \u003ca href=\"https://github.com/CedarGroveStudios/NotFlix\" target=\"_blank\"\u003eNotFlix\u003c/a\u003e (Fake TV) code when the TV display is dark for 5 minutes or more.\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n      ","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCircuitPython Code\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"# SPDX-FileCopyrightText: 2023 Cedar Grove Maker Studios\n# SPDX-License-Identifier: MIT\n\n# TV Backlight\n# Feather M4 + AS7341 Color Sensor + NeoPixel strip\n\nimport board\nimport math\nfrom simpleio import map_range\nfrom adafruit_as7341 import AS7341, Gain\nimport neopixel\n\nstrip = neopixel.NeoPixel(board.D12, 30, brightness=1.0)\npixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.5)\n\n# Instantiate and set up the spectrometer sensor\ni2c = board.I2C()  # uses board.SCL and board.SDA\nsensor = AS7341(i2c)\n\n# The integration time step size in 2.78µs increments (JP 128, 999 max)\nsensor.astep = 256\n# The integration time step count (JP 50, 255 max)\nsensor.atime = 50\n# The internal gain setting (JP 256, 512 max)\nsensor.gain = Gain.GAIN_512X\n# The breakout board's LED brightness (JP 5, ? max)\nsensor.led_current = 0\n# Disable the LED\nsensor.led = False\n\n# Calculate the sensor channel count value maximum (13,107)\nMAX_COUNT = (sensor.astep + 1) * (sensor.atime + 1)\n\n# The color matching tolerance index; 0 to 104,8856 (8 * max_sensor_count)\nTOLERANCE = 40\n\n\ndef convert_count_to_rgb(count_tuple):\n    \"\"\"Converts the 8-channel sensor measurement count tuple into RGB888 for\n    use by a NeoPixel.\"\"\"\n    r8 = int(map_range(count_tuple[7], 0, MAX_COUNT, 0, 255))\n    g8 = int(map_range(count_tuple[4], 0, MAX_COUNT, 0, 255))\n    b8 = int(map_range(count_tuple[2], 0, MAX_COUNT, 0, 255))\n    return r8, g8, b8\n\n\n# The initial starting color (black)\nprevious_color = [0, 0, 0, 0, 0, 0, 0, 0]\n\nwhile True:\n    # Get counts from the eight visible channels\n    target_color = sensor.all_channels[0:8]\n    # Light up the on-board NeoPixel with the target color\n    pixel[0] = convert_count_to_rgb(target_color)\n\n    # Create list of channel deltas using list comprehension\n    channel_deltas = [\n        (target_color[idx] - count) for idx, count in enumerate(previous_color)\n    ]\n    # Resolve squared deltas to a Euclidean difference\n    color_distance = math.sqrt(sum([d**2 for d in channel_deltas]))\n    # Check fof a color match\n    color_match = bool(color_distance \u003c= TOLERANCE)\n\n    # Determine the step sizes needed to move from the previous color to the\n    # target color\n    if not color_match:\n        # Create a list of step sizes for each channel if colors aren't matched\n        steps = [8 * (d / color_distance) for d in channel_deltas]\n    else:\n        # Create a list of zero-sized steps if colors are matched\n        steps = [0 for d in channel_deltas]  # create a list of zero-sized steps\n\n    # Calculate a new previous color by adding a step to the previous previous_color\n    previous_color = [color + steps[idx] for idx, color in enumerate(previous_color)]\n\n    # Light up the neopixel strip with the new previous color\n    strip.fill(convert_count_to_rgb(previous_color))","metadata":{"language":"auto","linenums":false}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/235/original/IMG_1659.jpeg?1697135092","metadata":{"caption":""}},{"element_type":"product","content":"https://www.adafruit.com/product/4698","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/3919","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/3857","metadata":{}}]