[{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/409/original/MyState-AnyControl.png?1732502701","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n        \u003ch1\u003eOverview\u003c/h1\u003e\n\u003cp\u003eThe \u003ccode\u003eMyState\u003c/code\u003e library delivers a framework to simplify configuration and control of appliance-like devices.\u0026nbsp;\u003ccode\u003eMyState\u003c/code\u003e makes it quick-and-easy to define device state that is readily controllable from the outside world.\u003c/p\u003e\n\u003cp\u003eWriting code to control state and react to sensor inputs is time consuming. Why not (mostly) solve the problem once, and re-use that infrastructure to build up your next project faster?\u003c/p\u003e\n\u003ch3\u003eFeatures\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eRoute raw sensed input signals through custom signal-generating filters, and provide a solid, uniform user-interface experience.\u003c/li\u003e\n\u003cli\u003eLoad custom device configuration/controlled state on startup by calling\u0026nbsp;\u003ccode\u003eListenerRoot.script_load()\u003c/code\u003e.\n\u003cul\u003e\n\u003cli\u003eA good way to \"recall presets\" at the press of a button when manual configuration is a bit of a pain.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eLet anyone control your device using \u003ccode\u003eSigLink\u003c/code\u003e interface (by means of a serial/other IO connection).\n\u003cul\u003e\n\u003cli\u003eEx: Let a PC control your device using \u003ccode\u003eMyState\u003c/code\u003e \"signals\" sent across the USB/serial connection.\u003c/li\u003e\n\u003cli\u003eConfigure your device using a custom-built GUI or web interface.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eApplies more formalized (hopefully readable) patterns of \"filtering\" input/sense signals, and applying a \"reactive paradigm\" to respond accordingly.\u003c/li\u003e\n\u003cli\u003eAspires to enable a future of composable, modular devices where extension/customization is the norm. Getting our products to cooperate should not be a constant battle requiring mounds of ugly hacks.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003e✨Highlights\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eCall\u0026nbsp;\u003ccode\u003eSigLink.process_signals()\u003c/code\u003e to enable quick-and-easy device control via serial/IO connection.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3\u003eDetails\u003c/h3\u003e\n\u003cp\u003eThe framework provides access to device state using something the author calls a \"Model-React-Controller\" (MRC) -- analogous to a \u003ca href=\"https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller\" target=\"_blank\"\u003eModel-View-Controller\u003c/a\u003e.\u003c/p\u003e\n      \n\n\n\n\n","metadata":{}},{"element_type":"alert","content":"\u003cp\u003e\"React\" is used instead of \"View\" since uC devices more generally described as reacting to changes in the model/state data.\u003c/p\u003e","metadata":{"class":"element alert-element build-alert alert-info","markdown":"\"React\" is used instead of \"View\" since uC devices more generally described as reacting to changes in the model/state data.","alert_type":"info"}},{"element_type":"text","content":"\n        \u003ch2\u003eCode Repository\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eDevelopment repository on github:\u0026nbsp;\u003ca href=\"https://github.com/alainman-krh/MyState\" target=\"_blank\"\u003eMyState\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eProject examples (self contained): \u003ca href=\"https://github.com/alainman-krh/Projects_Circuits/tree/main/projects/HomeLights_Wired\" target=\"_blank\"\u003eHomeLights_Wired\u003c/a\u003e. --- \u003ca href=\"https://github.com/alainman-krh/Projects_Circuits/releases/tag/HomeLights_Wired-v0.1\" target=\"_blank\"\u003eDownload:v0.1\u003c/a\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch1\u003eSampleProj: HomeLights_Wired\u003c/h1\u003e\n      ","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/412/original/LightCtrl-3boards-PIC.png?1732677226","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eThe \u003cstrong\u003eHomeLights_Wired\u003c/strong\u003e project emulates a simplistic home light automation solution. To demonstrate state/signalling capabilities of the \u003ccode\u003eMyState\u003c/code\u003e libraries, the solution was split across 3 independent microcontrollers:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eA \u003ca href=\"https://www.adafruit.com/product/4333\" target=\"_blank\"\u003eCircuit Playground Bluefruit (#4333)\u003c/a\u003e board is used to emulate the lights in your house.\u003c/li\u003e\n\u003cli\u003eAn\u0026nbsp;\u003ca href=\"https://www.adafruit.com/product/5100\" target=\"_blank\"\u003eAdafruit MacroPad (#5100)\u003c/a\u003e acts as a control panel the user can use to toggle on/off lights, as well as dim them to a desired level.\u003c/li\u003e\n\u003cli\u003eFinally, a \u003ca href=\"https://www.adafruit.com/product/5525\" target=\"_blank\"\u003eRP2040-pico (#5525)\u003c/a\u003e board is used as the \"main controller\" - taking inputs from the macro pad, and updating the emulated house lights on the Circuit Playground.\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003eAt the moment, the main controller also uses a \u003ca href=\"https://www.adafruit.com/product/5752\" target=\"_blank\"\u003eNeoRotary 4 breakout (#5752)\u003c/a\u003e to change RGB values of individual lights.\u003c/li\u003e\n\u003cli\u003eMore inputs methods could certainly be added if desired. For example, you could use an IR remote's RED/GREEN/BLUE app buttons in conjunction with the volume +/- buttons to change the RGB values from a distance.\u003c/li\u003e\n\u003cli\u003eYou could even use the channel +/- buttons to switch between which light color is currently being modified.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eTo make uploading code a bit easier, each set of microcontroller-specific code (excluding common libraries) is stored in its own subfolder (see \u003ca href=\"https://github.com/alainman-krh/MyState/tree/main/demos\" target=\"_blank\"\u003edemos folder\u003c/a\u003e):\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/5525\" target=\"_blank\"\u003eRP2040-pico (#5525)\u003c/a\u003e \"main controller\":\u0026nbsp;\u003ccode\u003eLightCtrl3Boards_2040pico/\u003c/code\u003e subfolder.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/5100\" target=\"_blank\"\u003eAdafruit MacroPad (#5100)\u003c/a\u003e (mostly) \"dumb terminal\":\u0026nbsp;\u003ccode\u003eLightCtrl3Boards_AFMacropad/\u003c/code\u003e subfolder.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/4333\" target=\"_blank\"\u003eCircuit Playground Bluefruit (#4333)\u003c/a\u003e - acting as a light controller: \u003ccode\u003eLightCtrl3Boards_CPbluefruit/\u003c/code\u003e subfolder.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eBlock level diagram\u003c/h2\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/410/original/LightCtrl-3boards.png?1732502785","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCode: Defining system state\u003c/h2\u003e\n\u003cp\u003eThe main state of this multi-MCU solution resides on the main RP2040 controller board. Ignoring the less important aspects: this main internal state keeps track of:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eRGB values for the light color,\u003c/li\u003e\n\u003cli\u003ethe light intensity levels, as well as\u003c/li\u003e\n\u003cli\u003ethe on/off state of the light.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis information is stored in the \u003ca href=\"https://github.com/alainman-krh/Projects_Circuits/blob/main/HomeLights_Wired/pkg_install/LightCtrl3Boards_2040pico/StateDef.py\" target=\"_blank\"\u003eStateDef.py file\u003c/a\u003e.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"STATEBLK_CFG = StateBlock(\"CFG\", [\n    #Full white for now (overwritten by config_reset.state!):\n\tBGRP_RGB(\"kitchen\", dflt=(255,255,255)),\n\tBGRP_RGB(\"livingroom\", dflt=(255,255,255)),\n\tBGRP_RGB(\"garage\", dflt=(255,255,255)),\n    #Other rooms lights here...\n    ]\n)\nSTATEBLK_MAIN = StateBlock(\"Main\", [\n\tBFLD_Toggle(\"kitchen.enabled\", dflt=1),\n\tBFLD_Percent_Int(\"kitchen.level\", dflt=100),\n\tBFLD_Toggle(\"livingroom.enabled\", dflt=1),\n\tBFLD_Percent_Int(\"livingroom.level\", dflt=100),\n\tBFLD_Toggle(\"garage.enabled\", dflt=1),\n\tBFLD_Percent_Int(\"garage.level\", dflt=100),\n    #Other rooms lights here...\n)\n\n#Signal entry point for anything wanting to control this device (ex: PC/other uController, ...):\nMYSTATE = ListenerRoot([STATEBLK_CFG, STATEBLK_MAIN])","metadata":{"language":"python","linenums":false}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eNotice how we are able to split up states in multiple sections:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eCFG\u003c/code\u003e: storing the light RGB values, and\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eMain\u003c/code\u003e: tracking light intensity, and on/off (enable) state.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eTo ensure messages get routed to the appropriate section, a \"ROOT\" object (called\u0026nbsp;\u003ccode\u003eMYSTATE\u003c/code\u003e in this example) keeps a list of the two state blocks.\u003c/p\u003e\n\u003cp\u003eAlso note that the \u003ccode\u003eBGRP_*\u003c/code\u003e and \u003ccode\u003eBFLD_*\u003c/code\u003e functions are preset convenience functions that build state variable groups (like R,G,B triplets), and individual state fields of a certain type. They are used to make object construction a bit more readable.\u003c/p\u003e\n\u003ch2\u003eCode: State-changing signals\u003c/h2\u003e\n\u003cp\u003eThe \u003ccode\u003eMyState\u003c/code\u003e library contains pre-defined signal objects/types that can be used to react to events, modify state with little programming effort. These signals exist as python objects, but also as strings that can be sent through IO channels (ex: UART/RS232/other communications interface/...).\u003c/p\u003e\n\u003cp\u003eThe string representation of signals typically contains 4 parts:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003ccode\u003eTYPE\u003c/code\u003e: The signal type identifier.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003esection\u003c/code\u003e: The section (or state block) being targeted.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eid\u003c/code\u003e: The main signal identifier.\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eval\u003c/code\u003e: The signal value.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAs an example, a signal for incrementing kitchen light intensity by a value of 5 might look something like:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\"INC Main:kitchen.level 5\".\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe following lists the available signals in \u003ccode\u003eMyState.Signals\u003c/code\u003e:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003eSigEvent\u003c/code\u003e: \"SIG [SECTION]:[ID] [VALUE]\"\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003eGeneric signal that can be sent between devices/microcontrollers/code.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigValue\u003c/code\u003e: \"SVL [SECTION]:[ID] [VALUE]\"\n\u003cul\u003e\n\u003cli\u003eA way to send a value (ex: of a state variable) without necessarily setting anything.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigSet\u003c/code\u003e: \"SET [SECTION]:[ID] [VALUE]\"\n\u003cul\u003e\n\u003cli\u003eRequest to change the state variable of a \u003ccode\u003eStateBlock\u003c/code\u003e instance.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigGet\u003c/code\u003e: \"GET [SECTION]:[ID]\"\n\u003cul\u003e\n\u003cli\u003eRequest to get the state variable value from a \u003ccode\u003eStateBlock\u003c/code\u003e instance.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigIncrement\u003c/code\u003e: \"INC [SECTION]:[ID] [VALUE]\"\n\u003cul\u003e\n\u003cli\u003eRequest to increment the state variable of a\u0026nbsp;\u003ccode\u003eStateBlock\u003c/code\u003e instance.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigToggle\u003c/code\u003e: \"TOG [SECTION]:[ID] [VALUE]\"\n\u003cul\u003e\n\u003cli\u003eRequest to toggle the state variable of a\u0026nbsp;\u003ccode\u003eStateBlock\u003c/code\u003e instance.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigUpdate\u003c/code\u003e: \"UPD [SECTION]:[ID] [VALUE]\"\n\u003cul\u003e\n\u003cli\u003eRequest to have a controller send updated values to all of its listeners.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003eSigDump\u003c/code\u003e: \"DMP [SECTION]\"\n\u003cul\u003e\n\u003cli\u003eRequest to have a controller dump send all updated values to an IO stream.\u003c/li\u003e\n\u003cli\u003eNOTE: \"DMP ROOT\" tells the \u003ccode\u003eListenerRoot\u003c/code\u003e object to dump state variables of all \u003ccode\u003eStateBlock\u003c/code\u003es under its control.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"alert","content":"\u003cp\u003eThe idea of the \u003ccode class=\"inline\"\u003eSigDump\u003c/code\u003e signal is to provide an automatic discovery system for your internal state variables that doesn't require extra documentation on your part. A step towards interoperability and oneness with the outside world 🧘‍♀️Ω🧘‍♂️.\u003c/p\u003e\n\n\u003cp\u003eStill work to be done for auto-discovery of other signals, but at least \u003ccode class=\"inline\"\u003eMyState\u003c/code\u003e provides \u003cem\u003esome\u003c/em\u003e minimal \u003ca href=\"https://en.wikipedia.org/wiki/Type_introspection\"\u003e\"introspection\"\u003c/a\u003e on the contents of \u003ccode class=\"inline\"\u003eStateBlock\u003c/code\u003e objects.\u003c/p\u003e","metadata":{"class":"element alert-element build-alert alert-info","markdown":"The idea of the `SigDump` signal is to provide an automatic discovery system for your internal state variables that doesn't require extra documentation on your part. A step towards interoperability and oneness with the outside world 🧘‍♀️Ω🧘‍♂️.\n\nStill work to be done for auto-discovery of other signals, but at least `MyState` provides *some* minimal [\"introspection\"](https://en.wikipedia.org/wiki/Type_introspection) on the contents of `StateBlock` objects.","alert_type":"info"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCode: Signal filtering\u003c/h2\u003e\n\u003cp\u003eSignal filtering takes some input signal in order to convert them to a more practical form. For example, the input signal from a rotary encoder having moved by a certain \u003ccode\u003edelta\u003c/code\u003e value can be \u003ccode\u003efiltered\u003c/code\u003e (or converted) to a corresponding change in light intensity. Since the change in intensity might need to go up/down by 5% steps for every click of the rotary encoder, the filtering function would typically be used to scale this input delta value.\u003c/p\u003e\n\u003cp\u003eFor this particular project, the main signal filtering code can be found in \u003ca href=\"https://github.com/alainman-krh/Projects_Circuits/blob/main/HomeLights_Wired/pkg_install/LightCtrl3Boards_2040pico/StateReact.py\" target=\"_blank\"\u003e\u003cstrong\u003eLightCtrl3Boards_2040pico\\StateReact.py\u003c/strong\u003e\u003c/a\u003e. In this particular case, filtering is performed by a unique instance of the \u003ccode\u003eSenseFilter\u003c/code\u003e class created in \u003ca href=\"https://github.com/alainman-krh/Projects_Circuits/blob/main/HomeLights_Wired/pkg_install/LightCtrl3Boards_2040pico/main.py\" target=\"_blank\"\u003emain.py\u003c/a\u003e. A highly simplified version of how to use this object is presented here:\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"#Over simplified example -- for illustration purposes:\n\n#Construction the SenseFilter object:\nSENSE_FILT = SenseFilter(STATE_SYNC.roomcache_map)\n\n#...\nwhile True: #The main loop\n\t#If detect SigEvent(\"MP\", \"BTNPRESS\", btn_idx) from macropad:\n\tSENSE_FILT.filter_keypress(btn_idx)\n\n   \t#If detect SigEvent(\"MP\", \"ENCCHANGE\", delta) from macropad:\n\tSENSE_FILT.filter_MPencoder(sig.val)\n\n\t#If detect cange on I2C-attached NeoRotary 4:\n    SENSE_FILT.filter_I2Cencoder(encoder_idx, delta)","metadata":{"language":"python","linenums":false}},{"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        \u003cp\u003eYou can look into these filter functions to see how they get translated into state change (\u003ccode\u003eSigSet\u003c/code\u003e) signals. These signals eventually trigger changes to the \u003ccode\u003eSTATEBLK_CFG\u003c/code\u003e\u0026nbsp; \u0026amp; \u003ccode\u003eSTATEBLK_MAIN\u003c/code\u003e objects described above. Reminder: the \"CFG\" block stores the RGB \"configuration\" of the individual lights, whereas the \"Main\" block stores the on/off state and intensity setting of the lights.\u003c/p\u003e\n\u003ch2\u003eCode: State react\u003c/h2\u003e\n\u003cp\u003eAfter the state itself gets updated, it automatically notifies any \"listener\" registered with it. In this example, the listener is an instance of the \u003ccode\u003eMainStateSync(StateObserverIF)\u003c/code\u003e class located in \u003cstrong\u003eLightCtrl3Boards_2040pico\\StateReact.py\u003c/strong\u003e. Being derived from the \u003ccode\u003eStateObserverIF\u003c/code\u003e interface, this class needs to implement a \u003ccode\u003e.handle_update()\u003c/code\u003e function to react to the state changes:\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","metadata":{}},{"element_type":"code","content":"#Over simplified example -- for illustration purposes:\n\nclass MainStateSync(StateObserverIF):\n\t#...\n\n\tdef handle_update(self, section:str):\n\t\t#NOTE: Triggered after state values get changed\n\n        #Compute effective RGB values of all the lights (inefficient, but simple):\n\t\tfor (idx, refc) in self.roomcache_map.items():\n\t\t\t#NOTE: roomcache_map stores strings to keep from calculating\n\t\t\t#      on-the-fly when sending out signals. Not absolutely necessary.\n\n\t\t\t#Update both macropad lights \u0026 actual lights on Circuit Playground:\n\t\t\tfor com in self.update_comlist:\n\t\t\t\t#com is an instance of EasyCktIO.UART.SigCom_UART\n\t\t\t\t#that knows how to send signals:\n\t\t\t\tcom.send_signal(self.sig_lightval_update)","metadata":{"language":"python","linenums":false}},{"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        \u003ch2\u003eMore photos: Re-configuring lights\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","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/413/original/LightCtrl-3boardsAlter-PIC.png?1732677412","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        \u003ch2\u003ePossible enhancements\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eBuild a special GUI on PC that automatically reads in\u0026nbsp;\u003ccode\u003eMyState\u003c/code\u003e variables, and creates sliders, toggle switches, etc to alter settings.\u003c/li\u003e\n\u003cli\u003eFind a way to automatically register \u003cem\u003eany\u003c/em\u003e signal being created unless is \"private\" (not meant to be used externally). Let these signals also be written out on a serial interface when a \"DMP ROOT\" message is received.\u003c/li\u003e\n\u003c/ul\u003e\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        \u003ch1\u003eAdditional resources\u003c/h1\u003e\n\u003cp\u003eFinding parts needed for a physical project is often a non-trivial part of the design process. If you are like me, you might struggle with this too. Hopefully the suggestions that follow will be useful for your own projects!\u003c/p\u003e\n\u003ch2\u003eResources: PCBs \u0026amp; mounting\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/5774\" target=\"_blank\"\u003eAdafruit swirl grids (#5774 +3more)\u003c/a\u003e: Keep your project together and your wires connected.\n\u003cul\u003e\n\u003cli\u003eGreat for the prototyping stage of your design.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/3658\"\u003eM2.5 standoff/screws (#3658)\u003c/a\u003e: Also available in black. You might need other sizes (M2, M3) - but M2.5 appears to be the most common size for hobby PCBs.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/2944\" target=\"_blank\"\u003eThis mounting plate (#2944)\u003c/a\u003e: One of the few practical solutions I have found to mount an Adafruit MacroPad to a swirl grid.\n\u003cul\u003e\n\u003cli\u003eMacroPads can be mounted using M3 screws... but they just don't quite like being tied to the swirl grids. Grids work best with M2.5 screws.\u003c/li\u003e\n\u003cli\u003eThin enough to slip right above the MacroPad bottom plate.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://bc-robotics.com/shop/1591l-proto-board/\" target=\"_blank\"\u003e1591L proto board\u003c/a\u003e: Practically sized breadboard (~2.5in x 1.75in). Reasonably priced.\n\u003cul\u003e\n\u003cli\u003eIncludes 4 x M3 mounting holes: Designed for \u003ca href=\"https://bc-robotics.com/shop/small-enclosure-black/\" target=\"_blank\"\u003e1591L enclosure\u003c/a\u003e (need model with flanged cover).\u003c/li\u003e\n\u003cli\u003ePerfect substrate for sticking under \"tiny breadboard\" (#65) - which then easily mounts to Adafruit swirl grids.\u003c/li\u003e\n\u003cli\u003eAlso an overall great form-factor for Today's typical microcontroller project sizes - especially if you need the mounting holes.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.universal-solder.ca/product/canaduino-permanent-breadboard-m-464/\"\u003eCanaduino-M proto board\u003c/a\u003e: Practically sized breadboard (~3in x 1.74in). Very well priced.\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003eIncludes 4 x M3 mounting holes -- really helps with keeping things together.\u003c/li\u003e\n\u003cli\u003ePerfect substrate for sticking under a \u003ca href=\"https://www.infinitecables.com/products/surface-box-1-port-white\" target=\"_blank\"\u003e50 x 30mm surface box\u003c/a\u003e (RJ45 housing) - which then easily mounts to Adafruit swirl grids.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/2670\" target=\"_blank\"\u003eBakelite Perfboard (#2670)\u003c/a\u003e: Practically sized for sticking under \u003ca href=\"https://www.adafruit.com/product/5422\" target=\"_blank\"\u003ehalf-sized breadboards (#5422)\u003c/a\u003e.\u003cbr\u003e\n\u003cul\u003e\n\u003cli\u003eIncludes 4 mounting holes - which easily attach to Adafruit swirl grids.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/3768\" target=\"_blank\"\u003e90°/L-bracket (#3768)\u003c/a\u003e: Designed for motors - but great at holding up a Circuit Playground boards perpendicularly atop Adafruit swirl grids.\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2\u003eResources: Networking\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.adafruit.com/product/5987\" target=\"_blank\"\u003eRS232 Pal (#5987)\u003c/a\u003e: Simple. Inexpensive. Just what you need.\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.infinitecables.com/products/surface-box-1-port-white\" target=\"_blank\"\u003e50 x 30mm surface box\u003c/a\u003e (RJ45 housing)\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://www.amazon.ca/VCE-Keystone-Ethernet-Punch-Down-Certified/dp/B07Y44V68W\" target=\"_blank\"\u003eVCE RJ45 keystone jacks\u003c/a\u003e: Good quality. Punch down stand really helps.\n\u003cul\u003e\n\u003cli\u003eMight consider buying a better punch-down tool that automatically cuts excess wire.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eSparkfun \u003ca href=\"https://www.sparkfun.com/products/716\" target=\"_blank\"\u003eRJ45 breakout\u003c/a\u003e + \u003ca href=\"https://www.sparkfun.com/products/643\" target=\"_blank\"\u003e(separate) jack\u003c/a\u003e: Works well on solderless breadboard.\n\u003cul\u003e\n\u003cli\u003e...but needs something to keep front of jack from tipping down.\u003c/li\u003e\n\u003cli\u003eSuggest trimming \u003ca href=\"https://www.adafruit.com/product/5582\" target=\"_blank\"\u003estacking headers\u003c/a\u003e to 2 pins, bent 90°, with pins themselves clipped to fit in breadboard, and using as a shim between the nubs under the jacks.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eCat5e cable: \u003ca href=\"https://www.infinitecables.com/products/rj45-cat5e-350mhz-no-boot-patch-cable?variant=42826902634737\" target=\"_blank\"\u003eThis one\u003c/a\u003e seems good. With devices/breakout boards as small as they have become, you'll want something relatively thin \u0026amp; flexible to keep your overall builds small as well.\n\u003cul\u003e\n\u003cli\u003e\n\u003cem\u003eSome\u003c/em\u003e (typ. flat) RJ11 phone cables can be thinner and more flexible than CAT5, but finding one that is might be a challenge.\u003c/li\u003e\n\u003cli\u003eAs for round CAT3 phone cables: they appear to mostly use solid core conductors - making them less flexible than a good CAT5e alternative.\u003c/li\u003e\n\u003cli\u003eIn any case: RJ11/12 jacks are surprisingly not that much smaller than RJ45 - might as well just stick with the more ubiquitous RJ45+CAT5e components.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n      \n","metadata":{}}]