{"id":17723769,"url":"https://github.com/ncw/mirror","last_synced_at":"2025-03-14T05:32:02.830Z","repository":{"id":140294281,"uuid":"600374816","full_name":"ncw/mirror","owner":"ncw","description":"Neopixel based Infinity Mirror running on Raspbery Pi Pico-W with Micropython","archived":false,"fork":false,"pushed_at":"2023-02-12T13:51:41.000Z","size":2718,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-02T06:05:09.387Z","etag":null,"topics":["micropython","micropython-rpi-pico","neopixel","raspberry-pi-pico"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ncw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-11T09:44:37.000Z","updated_at":"2023-02-13T06:34:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"99f1f67e-d215-48e0-baaa-b64137ad2a55","html_url":"https://github.com/ncw/mirror","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fmirror","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fmirror/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fmirror/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncw%2Fmirror/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ncw","download_url":"https://codeload.github.com/ncw/mirror/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243532517,"owners_count":20306151,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["micropython","micropython-rpi-pico","neopixel","raspberry-pi-pico"],"created_at":"2024-10-25T15:43:59.830Z","updated_at":"2025-03-14T05:32:02.803Z","avatar_url":"https://github.com/ncw.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Infinity Mirror Conversion\n\nThis is code to run the LEDs in an infinity mirror while running on a\nRaspberry Pi Pico-W. It also contains a simulator for creating new\ndisplay modes.\n\n![Infinity Mirror](images/mirror.gif?raw=true \"Infinity Mirror\")\n\nThe main files are as follows\n\n- `mirror.py` - the main code to run on the pico\n- `modes/` - a directory of \"modes\" for the mirror - edit `__init__.py` to add new ones\n- `README.md` - this file\n- `rp2mirror_boot` - set the pico to boot the code\n- `rp2mirror_run` - send the code to the pico\n- `rp2run` - run a bit of code on the pico\n- `secrets.py` - contains WiFi access for the pico - not checked in\n- `sim.py` - the simulator - run this to test the modes on your computer\n\nNote that `secrets.py` should have your WiFi access details for use by the pico only.\n    \n```py\nSSID = \"yourssid\"\nPASSWORD = \"your password\"\n```\n\n## The mirror\n\nThe infinity mirror has a half silvered mirror and a fully silvered\nmirror about 3 cm apart. Around the edge of that gap there are 34\nneopixels controlled by the pico. The pico also has three analogue\npotentiometers (knobs) which have the function:\n\n0. Brightness\n1. Hue\n2. Speed\n\nThese can be interpreted by the running mode however its wants, but it\nshould try to obey the `Brightness` knob so as not to suprise the\nuser.\n\nThere are two buttons also, mode forward and mode backwards.\n\n## Modes\n\nThe current installed modes are\n\n- `colour_temp_lights` - all lights on at an adjustable colour temperature\n- `hsv_lights` - all lights on with an adjustable Hue, Saturation and Value\n- `hsvwaves` - waves of HSV around the lights\n- `led_test` - turns one LED on at a time\n- `softglow` - soft RGB glow\n- `hsv_spin` - spinning Hue with controllable saturation and speed\n- `christmas` - red and green christmassy lights\n- `temperature` - shows the temperature. Number of on LEDs is temp in C with flashing showing partial.\n- `time` - shows analogue time with 3 LEDS - Red is Hours, Green is Mins, Blue is Seconds\n\n## Using the simulator\n\nFirst make sure you have pygame installed.\n\nThen run `python3 sim.py` to run the simulator.\n\nYou can control the simulator with the mouse\n\n- Click LEFT, RIGHT to change mode\n- Mouse wheel to change brightness (knob 0)\n- SHIFT mouse wheel for hue (knob 1)\n- CTRL mouse wheel for speed (knob 2)\n- SHIFT+CTRL mouse wheel for temperature\n\n## Writing a new mode\n\nTo write a new mode, copy and rename one of the existing ones and add\nit to `modes/__init.py` in the order that you want it.\n\nNote that the modes run under both python3 and micropython so a little\ncare is needed. Test first with the simulator.\n\nEach mode should have this structure:\n\n```py\nclass Mode:\n    NAME = \"Name of your mode - printed to the serial console\"\n    def __init__(self, mirror):\n        self.mirror = mirror\n        # more stuff\n    def update(self):\n        \"\"\"\n        Update mirror with the current state\n\n        This is called 25 times per second.\n        \"\"\"\n        # Plot your mode on the LEDs here\n```\n\nThe mode is passed in a `mirror` object which has the following\nmethods you can use. This is a different object when running under\nmicropython or the simulator, but python's duck typing takes care of\nit.\n\n```py\nclass Mirror:\n    def __setitem__(self, index, value):\n        \"\"\"\n        We use mirror[0] = color to set colours\n        \"\"\"\n    def __getitem__(self, index):\n        \"\"\"\n        Read the value set by __setitem__\n        \"\"\"\n    def fill(self, col):\n        \"\"\"\n        Set all the LEDs to col\n        \"\"\"\n    def local_time(self):\n        \"\"\"\n        Returns the broken down local time like time.localtime()\n        \"\"\"\n    def knob(self, i):\n        \"\"\"\n        Read the ADC as a floating point number 0..1\n        \"\"\"\n    def knob_brightness(self):\n        \"\"\"\n        Brightness knob as a floating point number 0..1\n        \"\"\"\n    def knob_hue(self):\n        \"\"\"\n        Hue knob as a floating point number 0..1\n        \"\"\"\n    def knob_speed(self):\n        \"\"\"\n        Speed knob as a floating point number 0..1\n        \"\"\"\n    def temperature(self):\n        \"\"\"\n        Return the temperature of the board in C as a floating point number\n        \"\"\"\n```\n\nThe `Mirror` object also has an attribute `n` which is the number of LEDs.\n\nNote that colours are specified as tuples `(red, green, blue)` and the\nrange should be from `0..255` for each value.\n\n## Build notes\n\nHere is a collection of notes made while building the project.\n\n### Micropython\n\nInstall micropython firmware from here\n\nhttps://www.raspberrypi.com/documentation/microcontrollers/micropython.html\n\nNote using Pico W version rp2-pico-w-20230116-unstable-v1.19.1-803-g1583c1f67.uf2\n\n### rshell\n\nrshell to communicate with Pico W and send / receive files.\n\n    sudo apt install python3-rshell\n    \nCould also use Thonny.\n\nrshell - can cp things to /pyboard\n\n### Micropython test\n\nUse `repl` then type\n\n```\nimport machine\nled = machine.Pin(\"LED\", machine.Pin.OUT)\nled.off()\nled.on()\n```\n\nMicropython quick start docs are here: https://docs.micropython.org/en/latest/rp2/quickref.html\n\n### Neopixel\n\nRP2 micropython comes with built in neopixel library\n\nThis should set the LED to a pink color\n\n```\nfrom neopixel import NeoPixel\nimport machine\npin = machine.Pin(0)\npixels = NeoPixel(pin, 1)\npixels.fill((255, 5, 20))\npixels.write()\n```\n\nThe ordering of RGB seems to be wrong - this is easily fixed with\n\n    NeoPixel.ORDER = (0, 1, 2, 3)\n\nSo\n\n```\nfrom neopixel import NeoPixel\nNeoPixel.ORDER = (0, 1, 2, 3)\nimport machine\npin = machine.Pin(0)\npixels = NeoPixel(pin, 1)\npixels.fill((255, 5, 20))\npixels.write()\n```\n\n### Booting\n\nTo start a python program at boot copy it as `main.py` using rshell\n\n```\nhome/ncw\u003e cp /pyboard/softglow.py /pyboard/main.py\nCopying '/pyboard/softglow.py' to '/pyboard/main.py' ...\n```\n\nThe pico will now run this program on powerup and rshell will no longer work.\n\n#### Make rshell work again after main.py\n\nIf `rshell` is not working because a `main.py` has been installed.\n\nUse\n\n    picocom /dev/ttyACM0 -b115200\n\nThen press CTRL-C until you see\n\n```\nTraceback (most recent call last):\n  File \"main.py\", line 27, in \u003cmodule\u003e\nKeyboardInterrupt: \nMicroPython v1.19.1-803-g1583c1f67 on 2023-01-16; Raspberry Pi Pico W with RP2040\nType \"help()\" for more information.\n\u003e\u003e\u003e \n```\n\nThen type this to remove the `main.py`\n\n```\nimport os\nos.listdir(\"/\")\nos.remove(\"main.py\")\n```\n\nThen enter CTRL-d to soft reset the pico.\n\nCTRL-a CTRL-x to exit picocom\n\n`rshell` should work again.\n\n### Developing with rshell\n\nCan use `rshell` interactively, but it can be scripted also\n\n```\nrshell --quiet cp softglow2.py /pyboard/softglow2.py\nrshell --quiet \"repl ~ exec(open('softglow2.py').read())\"\n```\n\nThis is embodied in the `rp2run` script.\n\n### Power\n\nFrom the data sheet\n\n\u003e VBUS is the 5V input from the micro-USB port, which is fed through a\n\u003e Schottky diode to generate VSYS. The VBUS to VSYS diode (D1) adds\n\u003e flexibility by allowing power ORing of different supplies into VSYS.\n\nand later\n\n\u003e The simplest way to safely add a second power source to Pico is to\n\u003e feed it into VSYS via another Schottky diode (see Figure 15). This\n\u003e will 'OR' the two voltages, allowing the higher of either the\n\u003e external voltage or VBUS to power VSYS, with the diodes preventing\n\u003e either supply from back-powering the other.\n\nWe will run the LEDs directly from an external 5V power supply. Since\nthe RP SYS input range is 1.8V to 5.5V we don't need to worry about a\ndiode drop, so any silicon diode should be fine.\n\n- So via a diode connect external 5V PSU to VSYS\n- Leave VBUS unconnected (since it connects directly to the USB power)\n\nThis will allow us to connect a computer and not blow up the computer\nwith the external 5V PSU.\n\n### WLAN\n\nYou will need to make a file called `secrets.py` to make the WLAN work\nwith the contents:\n\n```\nSSID = \"your access point SSID\"\nPASSWORD = \"you access point password\"\n```\n\nThis file isn't checked in to the repo and is in `.gitignore`.\n\n### Current draw\n\nThe Board and LEDs take 1.22A with them all white on at maximum\nbrightness. With all the LEDs off the current draw is 30 mA. So each\nLED is taking 35 mA maximum with the board taking 30 mA. Measured with\na 20A multimeter inline.\n\n| Activity | Amps |\n|----------|------|\n| LEDs off | 0.03 |\n| Time     | 0.07 |\n| Temp     | 0.40 |\n| Christmas | 0.30 |\n| HSV Spin | 0.60 |\n| All white | 1.22 |\n\nThe data sheet says\n\n\u003e Default output constant current value 12mA, high constant current\n\u003e accuracy, easy to reduce the power consumption of built-in lamp beads\n\nWhich aparently means 12mA **per** LED colour (Red, Green or blue) for\na total of 36 mA which agrees pretty well with the measured 35 mA.\n\nThis 12 mA per colour is quite obvious in a later table in the\ndatasheet (headings translated from Chinese).\n\n| Luminous Color | Dominant Wavelength (nm) | Luminous Intensity (mcd) | Working Current (mA) | Working Voltage (V) |\n|----|----|----|----|----|\n|R|620-630| 600- 800|12|2.0-2.2|\n|G|515-525|1300-2000|12|3.0-3.3|\n|B|460-470| 400- 500|12|3.0-3.3|\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncw%2Fmirror","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncw%2Fmirror","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncw%2Fmirror/lists"}