[{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eRemixing the guide from the Ruiz brothers: \u003ca href=\"https://learn.adafruit.com/aqi-case/overview\"\u003ehttps://learn.adafruit.com/aqi-case/overview\u003c/a\u003e and retrofitting it for the \u003ca href=\"https://www.adafruit.com/product/4884\"\u003eFeather RP2040\u003c/a\u003e \u0026amp; the \u003ca href=\"https://www.adafruit.com/product/2900\"\u003eAdafruit FeatherWing OLED - 128x32 OLED Add-on For Feather\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eThe OLED is quite limited in colors \u0026amp; the Feather RP2040 has a single LED available. Given these constraints this is what I was able to achieve.\u003c/p\u003e\n      \n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/152/original/converted.jpg?1725230467","metadata":{"caption":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n        \u003cp\u003eAll the text on the third row are my own interpretations of the values of each of the categories. Here's an example of how I assigned a text value to the data around the PM2.5 data.\u003c/p\u003e\n\u003cpre class=\"prettyprint language-python hljs\"\u003e\u003cspan class=\"hljs-keyword\"\u003edef\u003c/span\u003e \u003cspan class=\"hljs-title function_\"\u003erate_pm25\u003c/span\u003e(\u003cspan class=\"hljs-params\"\u003epm25_data\u003c/span\u003e):\n    \u003cspan class=\"hljs-keyword\"\u003eif\u003c/span\u003e pm25_data \u0026lt;= \u003cspan class=\"hljs-number\"\u003e12\u003c/span\u003e:\n        pm25_color = green\n        pm25_extra = \u003cspan class=\"hljs-string\"\u003e\"OK\"\u003c/span\u003e\n    \u003cspan class=\"hljs-keyword\"\u003eelif\u003c/span\u003e pm25_data \u0026lt;= \u003cspan class=\"hljs-number\"\u003e35\u003c/span\u003e:\n        pm25_color = yellow\n        pm25_extra = \u003cspan class=\"hljs-string\"\u003e\"MID\"\u003c/span\u003e\n    \u003cspan class=\"hljs-keyword\"\u003eelse\u003c/span\u003e:\n        pm25_color = red\n        pm25_extra = \u003cspan class=\"hljs-string\"\u003e\"BAD\"\u003c/span\u003e\n    \u003cspan class=\"hljs-keyword\"\u003ereturn\u003c/span\u003e pm25_color, pm25_extra\u003c/pre\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\n      \n\n\n\n","metadata":{}},{"element_type":"text","content":"\n        \u003cp\u003eBelow is the full code I used to implement this functionality. Here's a list of libraries you'll need (any listing without a \u003ccode\u003e.mpy\u003c/code\u003e at the end means that it is a directory):\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eadafruit_bus_device\u003c/li\u003e\n\u003cli\u003eadafruit_display_text\u003c/li\u003e\n\u003cli\u003eadafruit_pm25\u003c/li\u003e\n\u003cli\u003eadafruit_displayio_ssd1306.mpy\u003c/li\u003e\n\u003cli\u003eadafruit_pixelbuf.mpy\u003c/li\u003e\n\u003cli\u003eadafruit_scd4x.mpy\u003c/li\u003e\n\u003cli\u003eadafruit_ticks.mpy\u003c/li\u003e\n\u003cli\u003eadafruit_neopixel.mpy\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThese libraries can be found here: \u003ca href=\"https://circuitpython.org/libraries\"\u003ehttps://circuitpython.org/libraries\u003c/a\u003e (version 9.x was used for this project)\u003c/p\u003e\n      ","metadata":{}},{"element_type":"code","content":"import time\nimport board\nimport displayio\nimport neopixel\nimport terminalio\n\nfrom adafruit_ticks import ticks_ms, ticks_add, ticks_diff\nfrom adafruit_pm25.i2c import PM25_I2C\nimport adafruit_scd4x\nimport adafruit_displayio_ssd1306\n\nfrom adafruit_display_text import label\n\n# Set up pixel coloring\npixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.1, auto_write=False)\nred = (80, 0, 0)\nyellow = (75, 80, 0)\ngreen = (0, 80, 0)\n\nreset_pin = None\ni2c = board.STEMMA_I2C()\n\n# Set-up pm25 air sensor\npm25 = PM25_I2C(i2c, reset_pin)\n\n# Set-up scd4x CO2 sensor\nscd4x = adafruit_scd4x.SCD4X(i2c)\nscd4x.start_periodic_measurement()\n\ntime.sleep(5)\n\n# pm25 air sensor data set-up\ntry:\n    aqdata = pm25.read()\n    pm25Data = int(aqdata[\"pm25 standard\"])\nexcept RuntimeError:\n    pm25Data = 0\n\nco2Sensor = scd4x.CO2\ntempSensor = scd4x.temperature\nhumiditySensor = scd4x.relative_humidity\n\ndef rate_pm25(pm25_data):\n    if pm25_data \u003c= 12:\n        pm25_color = green\n        pm25_extra = \"OK\"\n    elif pm25_data \u003c= 35:\n        pm25_color = yellow\n        pm25_extra = \"MID\"\n    else:\n        pm25_color = red\n        pm25_extra = \"BAD\"\n    return pm25_color, pm25_extra\n\ndef rate_co2(co2_data):\n    if co2_data \u003c= 500:\n        co2_extra = \"OK\"\n    elif co2_data \u003c= 1000:\n        co2_extra = \"MEH\"\n    elif co2_data \u003c= 1400:\n        co2_extra = \"-15%\"\n    elif co2_data \u003c= 1600:\n        co2_extra = \"-50%\"\n    elif co2_data \u003c= 2000:\n        co2_extra = \"VENT\"\n    else:\n        co2_extra = \"BAD!\"\n    return co2_extra\n\ndef rate_temperature(temp_data):\n    if temp_data \u003c= 30:\n        temp_extra = \"COLD\"\n    elif temp_data \u003c= 80:\n        temp_extra = \"OK\"\n    elif temp_data \u003c= 90:\n        temp_extra = \"WARM\"\n    else:\n        temp_extra = \"HOT\"\n    return temp_extra\n\ndef rate_humidity(humidity_data):\n    if humidity_data \u003c 55:\n        humidity_extra = \"DRY\"\n    elif humidity_data == 55 and humidity_data \u003c= 65:\n        humidity_extra = \"OK\"\n    else:\n        humidity_extra = \"WET\"\n    return humidity_extra\n\ndef c_to_f(temp_data):\n    temperature_celsius = temp_data\n    temperature_fahrenheit = temperature_celsius * 9 / 5 + 32\n    return temperature_fahrenheit\n\n# display set-up\ndisplayio.release_displays()\ni2c = board.I2C()\ndisplay_bus = displayio.I2CDisplay(i2c, device_address=0x3C)\ndisplay = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)\n\ngroup = displayio.Group()\n\ndisplay.root_group = group\n\n# Background set-up\ncolor_bitmap = displayio.Bitmap(128, 32, 1)\ncolor_palette = displayio.Palette(1)\ncolor_palette[0] = 0x000000  # black\nbg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)\ngroup.append(bg_sprite)\n\nTOTAL_WIDTH = 128\nTOTAL_HEIGHT = 32\n\nSECTION_WIDTH = (TOTAL_WIDTH - 10) // 4\nSECTION_HEIGHT = (TOTAL_HEIGHT // 3) - 1\n\n# PM2.5 text set-up\npm25_title = label.Label(\n    terminalio.FONT, text=\"PM25\", color=0xFFFFFF, x=0, y=SECTION_HEIGHT\n)\npm25_text = label.Label(\n    terminalio.FONT, text=\"%d\" % pm25Data, color=0xFFFFFF, x=0, y=(SECTION_HEIGHT * 2)\n)\npm25_extra_text = label.Label(\n    terminalio.FONT, text=\"\", color=0xFFFFFF, x=0, y=(SECTION_HEIGHT * 3)\n)\ngroup.append(pm25_title)\ngroup.append(pm25_text)\ngroup.append(pm25_extra_text)\n\n# CO2 text set-up\nco2_title = label.Label(\n    terminalio.FONT, text=\"CO2\", color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT)\n)\nco2_text = label.Label(\n    terminalio.FONT, text=\"%d\" % co2Sensor, color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)\n)\nco2_extra_text = label.Label(\n    terminalio.FONT, text=\"\", color=0xFFFFFF, x=((SECTION_WIDTH * 2) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)\n)\ngroup.append(co2_title)\ngroup.append(co2_text)\ngroup.append(co2_extra_text)\n\n# Temperature text set-up\ntemp_title = label.Label(\n    terminalio.FONT, text=\"TEMP\", color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT)\n)\ntemp_text = label.Label(\n    terminalio.FONT, text=\"%d\" % c_to_f(tempSensor), color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)\n)\ntemp_extra_text = label.Label(\n    terminalio.FONT, text=\"\", color=0xFFFFFF, x=((SECTION_WIDTH * 3) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)\n)\ngroup.append(temp_title)\ngroup.append(temp_text)\ngroup.append(temp_extra_text)\n\n# Humidity text set-up\nhumidity_title = label.Label(\n    terminalio.FONT, text=\"HUMD\", color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT)\n)\nhumidity_text = label.Label(\n    terminalio.FONT, text=\"%d\" % humiditySensor, color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT * 2)\n)\nhumidity_extra_text = label.Label(\n    terminalio.FONT, text=\"\", color=0xFFFFFF, x=((SECTION_WIDTH * 4) - SECTION_WIDTH), y=(SECTION_HEIGHT * 3)\n)\ngroup.append(humidity_title)\ngroup.append(humidity_text)\ngroup.append(humidity_extra_text)\n\nsensor_texts = [pm25_text, co2_text, temp_text, humidity_text]\nsensor_data = [pm25Data, co2Sensor, tempSensor, humiditySensor]\nsensor_extra_texts = [pm25_extra_text, co2_extra_text, temp_extra_text, humidity_extra_text]\n\nsensor_clock = ticks_ms()\nsensor_check = 5000\nfirst_run = True\n\nwhile True:\n    if scd4x.data_ready:\n        if first_run or ticks_diff(ticks_ms(), sensor_clock) \u003e sensor_check:\n            co2Sensor = scd4x.CO2\n            tempSensor = c_to_f(scd4x.temperature)\n            humiditySensor = scd4x.relative_humidity\n\n            try:\n                aqdata = pm25.read()\n                pm25Data = int(aqdata[\"pm25 standard\"])\n            except RuntimeError:\n                print(\"Unable to read from PM2.5 sensor, no new data...\")\n                continue\n            \n            pm25_color, pm25_extra = rate_pm25(pm25Data)\n            pixel.fill(pm25_color)\n            pixel.show()\n\n            # updating the array of sensor data values\n            sensor_data = [pm25Data, co2Sensor, tempSensor, humiditySensor]\n            sensor_extra = [pm25_extra, rate_co2(co2Sensor), rate_temperature(tempSensor), rate_humidity(humiditySensor)]\n\n            for s in range(4):\n                sensor_texts[s].text = \"%d\" % sensor_data[s]\n                sensor_extra_texts[s].text = sensor_extra[s]\n                # print(\"updated %d data\" % sensor_data[s])\n                time.sleep(0.2)\n            sensor_clock = ticks_add(sensor_clock, sensor_check)\n\n        if first_run:\n            sensor_clock = ticks_ms()\n            first_run = False","metadata":{"language":"python","linenums":false}}]