From 8958874a77b09c72cd395526362a87641d299fee Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 14 Jul 2017 10:44:24 +0100 Subject: [PATCH] Add pin_factory param to all devices And some docs ... --- docs/api_input.rst | 16 +- docs/api_pins.rst | 62 +++++-- docs/images/device_pin_flowchart.dot | 19 ++ docs/images/device_pin_flowchart.pdf | Bin 0 -> 8134 bytes docs/images/device_pin_flowchart.png | Bin 0 -> 29123 bytes docs/images/device_pin_flowchart.svg | 66 +++++++ docs/images/raspi-config.png | Bin 33392 -> 37065 bytes docs/installing.rst | 72 +++++--- docs/notes.rst | 2 +- docs/recipes_advanced.rst | 8 +- docs/remote_gpio.rst | 134 +++++++++----- gpiozero/boards.py | 257 ++++++++++++++++++++------- gpiozero/devices.py | 9 +- gpiozero/input_devices.py | 75 ++++++-- gpiozero/output_devices.py | 91 ++++++++-- gpiozero/spi_devices.py | 4 +- 16 files changed, 619 insertions(+), 196 deletions(-) create mode 100644 docs/images/device_pin_flowchart.dot create mode 100644 docs/images/device_pin_flowchart.pdf create mode 100644 docs/images/device_pin_flowchart.png create mode 100644 docs/images/device_pin_flowchart.svg diff --git a/docs/api_input.rst b/docs/api_input.rst index 4791c1c..8151836 100644 --- a/docs/api_input.rst +++ b/docs/api_input.rst @@ -16,35 +16,35 @@ everyday components. Components must be wired up correctly before use in code. Button ====== -.. autoclass:: Button(pin, pull_up=True, bounce_time=None, hold_time=1, hold_repeat=False) +.. autoclass:: Button(pin, pull_up=True, bounce_time=None, hold_time=1, hold_repeat=False, pin_factory=None) :members: wait_for_press, wait_for_release, pin, is_pressed, is_held, hold_time, held_time, hold_repeat, pull_up, when_pressed, when_released, when_held Line Sensor (TRCT5000) ====================== -.. autoclass:: LineSensor(pin, queue_len=5, sample_rate=100, threshold=0.5, partial=False) +.. autoclass:: LineSensor(pin, queue_len=5, sample_rate=100, threshold=0.5, partial=False, pin_factory=None) :members: wait_for_line, wait_for_no_line, pin, line_detected, when_line, when_no_line Motion Sensor (D-SUN PIR) ========================= -.. autoclass:: MotionSensor(pin, queue_len=1, sample_rate=10, threshold=0.5, partial=False) +.. autoclass:: MotionSensor(pin, queue_len=1, sample_rate=10, threshold=0.5, partial=False, pin_factory=None) :members: wait_for_motion, wait_for_no_motion, pin, motion_detected, when_motion, when_no_motion Light Sensor (LDR) ================== -.. autoclass:: LightSensor(pin, queue_len=5, charge_time_limit=0.01, threshold=0.1, partial=False) +.. autoclass:: LightSensor(pin, queue_len=5, charge_time_limit=0.01, threshold=0.1, partial=False, pin_factory=None) :members: wait_for_light, wait_for_dark, pin, light_detected, when_light, when_dark Distance Sensor (HC-SR04) ========================= -.. autoclass:: DistanceSensor(echo, trigger, queue_len=30, max_distance=1, threshold_distance=0.3, partial=False) +.. autoclass:: DistanceSensor(echo, trigger, queue_len=30, max_distance=1, threshold_distance=0.3, partial=False, pin_factory=None) :members: wait_for_in_range, wait_for_out_of_range, trigger, echo, when_in_range, when_out_of_range, max_distance, distance, threshold_distance Base Classes @@ -63,7 +63,7 @@ to construct classes for their own devices. DigitalInputDevice ================== -.. autoclass:: DigitalInputDevice(pin, pull_up=False, bounce_time=None) +.. autoclass:: DigitalInputDevice(pin, pull_up=False, bounce_time=None, pin_factory=None) :members: SmoothedInputDevice @@ -75,12 +75,12 @@ SmoothedInputDevice InputDevice =========== -.. autoclass:: InputDevice(pin, pull_up=False) +.. autoclass:: InputDevice(pin, pull_up=False, pin_factory=None) :members: GPIODevice ========== -.. autoclass:: GPIODevice(pin) +.. autoclass:: GPIODevice(pin, pin_factory=None) :members: diff --git a/docs/api_pins.rst b/docs/api_pins.rst index 6a34a72..340d8b9 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -11,10 +11,23 @@ are concerned with. However, some users may wish to take advantage of the capabilities of alternative GPIO implementations or (in future) use GPIO extender chips. This is the purpose of the pins portion of the library. -When you construct a device, you pass in a pin specification. However, what the -library actually expects is a :class:`Pin` implementation. If it finds anything -else, it uses the existing ``Device.pin_factory`` to construct a :class:`Pin` -implementation based on the specification. +When you construct a device, you pass in a pin specification. This is passed to +a pin :class:`Factory` which turns it into a :class:`Pin` implementation. The +default factory can be queried (and changed) with ``Device.pin_factory``, i.e. +the ``pin_factory`` attribute of the :class:`Device` class. However, all +classes accept a ``pin_factory`` keyword argument to their constructors +permitting the factory to be overridden on a per-device basis (the reason for +allowing per-device factories is made apparent later in the :doc:`remote_gpio` +chapter). + +This is illustrated in the following flow-chart: + +.. image:: images/device_pin_flowchart.* + +The default factory is constructed when GPIO Zero is first imported; if no +default factory can be constructed (e.g. because no GPIO implementations are +installed, or all of them fail to load for whatever reason), an +:exc:`ImportError` will be raised. Changing the pin factory ======================== @@ -24,7 +37,7 @@ The default pin factory can be replaced by specifying a value for the .. code-block:: console - pi@raspberrypi $ GPIOZERO_PIN_FACTORY=native python + $ GPIOZERO_PIN_FACTORY=native python Python 3.4.2 (default, Oct 19 2014, 13:31:11) [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. @@ -37,8 +50,8 @@ export this value: .. code-block:: console - pi@raspberrypi $ export GPIOZERO_PIN_FACTORY=native - pi@raspberrypi $ python + $ export GPIOZERO_PIN_FACTORY=native + $ python Python 3.4.2 (default, Oct 19 2014, 13:31:11) [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. @@ -46,7 +59,7 @@ export this value: >>> gpiozero.Device.pin_factory >>> quit() - pi@raspberrypi $ python + $ python Python 3.4.2 (default, Oct 19 2014, 13:31:11) [GCC 4.9.1] on linux Type "help", "copyright", "credits" or "license" for more information. @@ -73,17 +86,30 @@ they are tried by default. | native | :class:`gpiozero.pins.native.NativeFactory` | :class:`gpiozero.pins.native.NativePin` | +---------+-----------------------------------------------+-------------------------------------------+ -If you need to change the default pin factory from within a script, set +If you need to change the default pin factory from within a script, either set ``Device.pin_factory`` to the new factory instance to use:: from gpiozero.pins.native import NativeFactory - from gpiozero import * + from gpiozero import Device, LED + Device.pin_factory = NativeFactory() + # These will now implicitly use NativePin instead of + # RPiGPIOPin + led1 = LED(16) + led2 = LED(17) + +Or use the ``pin_factory`` keyword parameter mentioned above:: + + from gpiozero.pins.native import NativeFactory from gpiozero import LED - # This will now use NativePin instead of RPiGPIOPin - led = LED(16) + my_factory = NativeFactory() + + # This will use NativePin instead of RPiGPIOPin for led1 + # but led2 will continue to use RPiGPIOPin + led1 = LED(16, pin_factory=my_factory) + led2 = LED(17) Certain factories may take default information from additional sources. For example, to default to creating pins with @@ -100,11 +126,13 @@ Like the ``GPIOZERO_PIN_FACTORY`` value, these can be exported from your .. warning:: - The astute and mischievous reader may note that it is possible to mix pin - implementations, e.g. using ``RPiGPIOPin`` for one pin, and ``NativePin`` - for another. This is unsupported, and if it results in your script - crashing, your components failing, or your Raspberry Pi turning into an - actual raspberry pie, you have only yourself to blame. + The astute and mischievous reader may note that it is possible to mix + strictly local pin implementations, e.g. using ``RPiGPIOPin`` for one pin, + and ``NativePin`` for another. This is unsupported, and if it results in + your script crashing, your components failing, or your Raspberry Pi turning + into an actual raspberry pie, you have only yourself to blame. + + Sensible uses of multiple pin factories are given in :doc:`remote_gpio`. RPi.GPIO diff --git a/docs/images/device_pin_flowchart.dot b/docs/images/device_pin_flowchart.dot new file mode 100644 index 0000000..1470b08 --- /dev/null +++ b/docs/images/device_pin_flowchart.dot @@ -0,0 +1,19 @@ +/* vim: set et sw=4 sts=4: */ + +digraph device_pins { + graph [rankdir=TB]; + node [shape=rect, shape=filled, fontname=Sans, fontsize=10]; + edge [fontname=Sans, fontsize=10]; + + constructor [label="LED(pin_spec, ...,\npin_factory=None)"]; + pin_factory_kwarg [shape=diamond,label="pin_factory == None?"]; + default_factory [label="self.pin_factory = Device.pin_factory"]; + override_factory [label="self.pin_factory = pin_factory"]; + factory_pin [label="self.pin = self.pin_factory.pin(pin_spec)"]; + + constructor->pin_factory_kwarg; + pin_factory_kwarg->default_factory [label="yes"]; + pin_factory_kwarg->override_factory [label="no"]; + default_factory->factory_pin; + override_factory->factory_pin; +} diff --git a/docs/images/device_pin_flowchart.pdf b/docs/images/device_pin_flowchart.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4a9d4a31d58d3b415470d1f77bb7ce7793e59b01 GIT binary patch literal 8134 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 E0R2oPz5oCK literal 0 HcmV?d00001 diff --git a/docs/images/device_pin_flowchart.png b/docs/images/device_pin_flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..4909f7851b3eef0ba4b28e9a716d879d1677c221 GIT binary patch literal 29123 zcmc%xc{JB;`v#1DsZ5zd5+S5Cld%YyB^648Aw!aR%8&?|XVM@gWJnSzV6d_{sBuw$u36S{EhFQ*`*pi|%3w{+r%W#@s3=W85V49| zSy^;Ad-km2i4(b9ul;FR9_8nsx_G`midW38OX8HizFBX%H-)lp-MTBopQvbPXhcOt zGYb>{{&jwzD7)#}zp*31%)IhvKmTmH-<+z>@;*UQt14A6Kths1r)9hM@=Ql(q22vX zR--(#b&O0*De398+MnCo>+-EWZ{=XfyWA}3_4nX>4rl z@9(FQm6hGLZJVNz5%2BWw>$I9X`{9rta_$rXvoMH9UKF++Q%PH!DVp!FlBOnoL}aAE{{5?!UAuSh-oVc8zqI5vJ>0zJ(4j*V zUulPL$uC~8y?F5=BqAc9uu#f#dRWJ9+4AEl59Eyd*RP2u6sk6GGtjKUXZC(Ww@=%2rQSv^=E{bymu zCiBS?0U4R%_Lpth*?S_k9Asl)VEEM1qU7Zz*PeSJ`rOM)rk^vk>6n?-E?wIG%5^j- zB!sTGq{MWvE|TK=`nBBqhlhEboSZ&2Hy=56jB#adkmcCD1M4V`vlB+|9~@-oJ#$Oy<+4(gUSh8dGXyA?`~%)b&>fmvjiJMO3`7XtXvoK5~R=4Gp6rzKOC` zLW1McrAvK(JOmp9gMtLNZ>RbC%C)*Wn8no8l!}&?c6ek&zx$HDKIish@xHjvlQo<{*8yXww~hJyt%Tuc>^aW z=h;%Xy|-@Pj*W?-oI7_eAUN2(r`YLvLBYDDkM-~GiRXFzG4q;fJ44C(kiC(EL;m-1 zww6~27Qvu<_ck9pcC5I=dtrLM@6gesM|+qwbB)WChCU=d-8(ou9Af|V6&2-}wzdE( zo#S8~Q=ULqj*%>RD~hKzSa=U{MDr`;6wnwM8R4RX_53~oadGU}LCyFr`;||2Nj|R303s<(Zuu&?8rgZf6_3iFO@yhC7OT2ws*zMZ8ckg0i z=X>=oW8p>i@6Rouv9Yn4o15$Vl%m{O?k#)BeImlVKFUd2uB>;uE6-g0qNSz3SWrX+ zV^4{T`nF8oEnAYavm>UbuV8guI&A3$PUF&6l)L+ks<6lUhllBsMb%-BiFR#rRj>@x~u;*sjB31x5l$3nrLa&&g4j;>culJ^$1 zYS~u&>Xm+X#)}sRjLW@3&*U11_Ashy7^n*z?aF@sTr^g^?0DiKQv@3&D~I>aty_*$ z2#x;l-)qXs-6#2+ot<$9F36jGND!UHPC^}P<($83U?-V@aQJ?_E8#HS{sK zq~suSK#R#FlR%^&lDj4rHY7B(-+nDMMOj%ng6}Z5l$2CRNQk0}%3A3Y=gw_De*Ab$ zY^>k2XM2~HmMEtrqyJ6z^1DxdBdMn7H4;+xvuFK7Lpz*>K2-&-cbfXCP3~y8BbOh6 zRA=;Zi>L`@wjnetYZrb|)mjP(y?x7){K10<$-B_h)V$o0!>bm_9mwyq6nkF*Wgsmh z!>seU=_e%a+q=&sr=(C(;tyYwLbUy9-2bNU&tUz@GiQP$Bbhn^7H4~X29dJr$G*JO zIeC)er%1VW?Hc9ug19KxJ64sKZbIToBSy_Ek^F5>8MGoeznK}i0y9Ju4qQ!pF zR_JsEvg)3}Qz9Atx6J9*FfcLI{{7MDgmm=VLvGL6=ahtm1i_T{TkX#bf{}VnS67yq zUVUw8(VhPFnKmykkLhpEWlzsTwzjsvhns~O-nK1YD^Ez^X5J#RwZ&OcL+GHg<)Z)z zHZ3i!?DGW-SFc_@si$Z2e7xM_5B2^F<=Ik3YHDg}^=TPZT-8nYrFpUk*I8ItAfYHf zq6nuwX?EBt5ZUnM%e}?bf!c7MG=n!tf&<7hZ5dPZUa^)2y+Z>7HwFdFcBT6_~Nlfd`(p_rDJd4|iIaw)#FaB(!T6gO!yP zazfST$0wX-MoyC-O(aEpB_CC>j zY+_?$FvOF%{lvov+;a8j&oArtZz(A$k?~%TIB?(q3G);3^8xqW5iP^R!&}9~Hn>mp z_#vV?-c}oghK3e<&g?>ri`w_d#QwBAbLLEEXQ#>X!c6Oh{Z{(J$8P0&^6~L;N!xE( zT3*&MHfG+mY13FwN!CdKEBMIkKRaLB_S|j!yv(6PW~e}{41t;1*#Y6<>)F`Y ziY;<3yos`CymJJQ2XLw9U+wa>HV`C90QYnB!c=EYPpVh`Dg{yzJk;Fl;khJtB0#m=dv@DqiY>c^k*FnFj zCxAi$M2?8zY-nzd1?=^5EGhS1d@(;Yk%eau2?+STZESp*mbR^q%e*>>$$a0weS)K2fP(Koe~!C0 zJ~sBgeEFXN{!&<2_}Es~);S04ryfu2R!cz6vD)xW$22uV1A~Lb>$voEbV&nNXrPZOLlfmr~pk(3NAkxKX-KCNB@2{@noc=R4y}enUA5Y zysxNG{O)0EXZL0QnS@_<&wsoN105Su4mVIz93IgcqF0|7)c1*?CnD2nNxEN|9<@DjdsL#jKv?{t# zI87>Vtm_%YOIJE`W)rp@VuqFy`%^D@B$gXNvo!trL_=d^b&1PRvADf_QuOcNzYp<7 z-?_tyCk%3Uv&?yS|Aid=-coPM=&xTX4!z~YKCAKzGo!Q=!Na1zMn_#b^x|&b{0&HI z_}XIwN+>l2xLp950q?WN{0Q=X1K^BaQ-FjN=@DMbF3?5S`vbKGD5Z2-^p0O=&K#)$ z!hUglv9YPC78pLyd(n+-cOV-_7neab(+v!P*iWm&E5>9lg5o+ zvxoQY-0An=!Irhuehrek08X*xk?R>4lC!eTn>Ph$tO*pcVpmd95(OruRG>*h@1kHG zaZ*!w`*tN`%E z`77St-fdGhSXhoFBK;46z^rs@fsmeS45MJte*5-~OX0d4c4;J3x|moHZ|H8El9KhMusA&}_u((K2)IJY zz<}q(L%AbBl_=8`${e6XY+@o4dazLI?P+-@LvBj-BZaEr7jF3b=XuUp$Bw$=#te&G z+uPfFBQP%N0mli742|-OsZ&ZVj^P|NS9kga^hOwi z*!$sKVZki?RcHf%)P}#6mF73bY9J}1g<;*Yg;86(iDlmjd~CZ)YBB5IJhZ>M&qigF zv$_>gl6IatC5wMOIDCzBb$Qaqz}A=gwDw1Sp5*^F>?2=G-J^NtUdf|lP0q>L=jQ1$ zjTf$T41D{bd>SZ4t(Wv1M9(%Xc#yL<%Is9<~{x|+~faHHvdDI{6G0YD^nng z%E3P>D~G-2Sa<7Zv);={PY=X?wz{jO@f4l7#(HxboAr{C1?TU^#>G_wI&BqF=66!! zX7{e5voZx_618dH^Lu`Y`z{h_yrhjjyS}PMHz*>F_0zu|Cq2r}&aRv9>gqy%&_26C zz>XbHzc(g5U06a=vi8H^)I1Qyb@nqV|MQue!9RT?BMhplwboNdwY0<#0Xt9O3&GB4 zte3=p-MV$_)P4Jl7Xy%aHB$tYy7=%O&x@Fwn*+M3U*tw({`%@vnjWiw9pT3IcH+NO zCR+CH-d&AfNGG?j{y#s@KKHV?^vYE^zCC;Pd;-g~^9(L?gj}Zm>6!hE+!Azhd@O(e z{%yUbrNN%cDx4PR;_AANLfEU3)+f3-K{17aO1EM-vy+o4Nc@zniFe-13zEBb?MgG; zC}0=-AbT{PSyBQ ztue8+eZMR&CUyjSG~J6MAYWdtE}oyFZna5??g=T_5)>4KmnG5Y>^9T_oq?rdi>LD|yK&`?BcjAecr_ydnux_L^rr=Xp#(DU z6S7|Ha|v;AWq{Xoqr#BOcGW@csuj^2O2(*wzWdU__;y2F5pk@50L$CfS-H-80O?ZPA_ zBveY>#?y@4;(%I|ot=aY3H>{ zobxG=q;Gupu4VD~c|o9;S8X#98e3WO?`3rUd{oFu*|>4z^mzB(^ArsiRe_`Dg8>Aw ziNbrnvv1xU3W)Pcsza&GZEr$3CH4|wa`*6GyDK6|UwHhcL~YUc(np#vL4+jazLL+? zkbazRze@!!zvZ6{bKcSO$ItAo# z@PeaolV5Sv0YO2*n1>I)C3|zmNr6<5V0O~ZLlg3-Sw-Weu>JIdBJCV|r@pw-X})kxJcV~@Ui^-5c}JAj_OZ+twG@33d9jciIvO6N;UmX?+l$G!?G z;7-YtfzPUeU>q0!*)eXBVO>~Q=$XDYJ8|UrappC&%(m0qz;TYhT7&8V}{eZ}b2(Vf_7gy81$SV6g$3^Sv>5Y~899v6Gh5r$j z$vVLd9IvT^Lv$pMw9;1AWWC47*&J-p2g_VvlF2bH>+;=rv=^YG53RRpb&$ZeZ2|Yo zug%(v?A|Ty8FJ^&ovMlo3VIShG#P|8z}J}lYDu5@R*03k;_906^yzx=k@l~OxA%i7 z>u-B{rgd9S9bkubjigN(Z|6B}?Z{H9YM>!%KME?)Nqv3$zlU60Tv8rAy3x~P_}X)Z z0WBdr{rH>J6&^4h6bdpLO@!F*d9Rw<+9S%!gZ?aI>jRbWAEZC}@Zm#DT-@LXQ9^~G zr6Z6H%hJ}qckfghM2{dG0D)-_A3hvwj-Brh zdi>k#tN!1=Uqn8jrDT=$;+OHp{aefPuZ(wX+_`h7%(Z`ewreMx8g%||->5b_@m2L( z5jc}ucke2rx%>0y4<3oL`^L$WCwp1cLLI*aHz3lgGeFKFJM6B8dm`d1=Je@XILdHc$397y(Eu?2AYStPx4KxSpV zdYTUoxrY539)6BCKn#grUq`1BJ>ScZ^5(dS!8@{GDfP~rv849%MYa}WVPVlfcaAi? z_=@*kT?vusXz#_xKWFAW6q0SAuV2Tx-}t?RghVG8-E#oqov1EP+XOinzU)Zys*;nF zA;I*YWFi zW|dDF86~EtrHR&M-B8!jiADNrdlij6xE+ssV6UX)?L{AuaGyVYGSSh|!RqZZe%;X8 z)^<)wiMr@LwlJ4@#MNup#0?A#V(q-qM7)3ZF0Ab8RFGI5`hxEGs3_*ymC=!r13WxD z`i6$@xy-X)ytuiUi|aWkUB~WtaZ6_042Qug2m|3h&MR^(p{TOa_-P*OHbzGqT%<)nTS%K^02rVG%KH=!PTSUb1 zLQkRn*LP|WT$RhOA3b^$kD9D?;>4yW7As5hw%|g07TX^D7#eyB?Z)kQ-;qMEdFM+u zHjP-G^Y8DTt>Q9&kJjB_Gx9EaY>|EYf{=6~A|i@2IzjfCfW4l1^?i_)l5-@=g(vzF_|A z73hw{yce#-Ud0UsqoY%c+Crb4_13jL`<#r=irl65@l+J90~hIn7&lW>KDD)}B0~d6 ztVQ5#k#%E4!LJ+dE-JA@C%6%;CQ%0{4-UG}fVcO+n+zXbIf3m~8f`*)tt(F2RR)E& zDYD)7cQQ2Ve{X%F7cXVUJ^KoGOa7prYs|#X&VFU`n^9PsWRyF-?Ms(3I$2Na z=?$)Y9Q;GXlJn=!KVHUinWM6!2FU>FCTC>O`1tsMl3bJdO5fVTVy3yf@%?*_UkBCE z9gd8QG&D5yWt8z(<>cg?eR+wAPvLq5_RFe|-Ob^4z(d2cCg`0I^gv+?+~9 z0m%#MH6SYLc%&qhN7K59&7DOK{2w6JN!qlx7Tcn!eI{USY6>A5Jn9ptbF{R)n2=NOMU!uWD;&wDI zgFU2T2@XSX6@jjIAlr{;9FaQebf8*@^gWHABVtFIOaArHRV~i?K&1ON<|U1{IF$@@$2}-)b=+% zK87XE>yXIn?q0YaibB;FzQ5cTf&h|2C@7A>`wrzt5Kh!<*7X1U8B|rJ^gdo}&HViQ z^TNV91WU;>YIdmILk_yN$P|HPW!|aRt>(C}`9%*LV7pgn^?AF8hle7FA;r^ig9SDn z&z*l91;?|WFeXHEwn^sZ<`(3Yr1++!2z1oQLY(usc8v&7>focmMu~aNImXsoq5aZ1 zd$uz^`22o;S&Dv(12I2fL4pV85=x>Ido*OgE2 zv$`xD#LOE8{GnO;Kx*&){VebUNKor^qc7Mdl+*n(gKx_`j1D(aQ_ag9ViHiwfCA6i zEr9R*({|=Un@x9QWqmy@01iUfcx z-d{r6m6!41!_T&#(X)KMoTFWpHqItZ-Hc5cd+*-P!ks8om7iK$Z=sjCiguwzC`VI9 zPHqeIuC!QD4gZwNK20I`Mw&j>yBW>>V|fTv(#aR5(XH1_r_yS{XSEg=v+!_t{GL!J zo?aQ-9ffkWZTt2xUdHka{fG>1#)tVk$*-_?Z1Y0WKToTkp^&k+zMh%pgm#|FQQXz& zbl#fq&wUL|>UK?Y)8ax+93XsThqE)TCiA@0*sTORL9sgTH{%Pb>bxWBJ*nDPc<<*6 zqI+xoZqE1WvFzceAvR&&-ET=Xg%S{V(2Fz5RLtUW93g{I$Ftf;MUJQ;|@|JxJ>7^2<6HEX2k32zOMxUuw2SAtn> zBGvk})cH0Y$H&|N*8|X4Jdkx~hK9nl@{P6S2A;R2^Y{Z9Du_^C3%?$BmR)mCtfN>& zkm_S7?s(;j1fD78!2=?5BSlqrc5*??B<(RSXl8DXK%fIsBhCr@6-oo{E(nDjz-;uC z52!@K1&?;*R%83IZ$FkfYM`iLgKeu}4%+}N@IW5)sq71H$}0;Ebaih)yAwd^0niVL ziXsaGcwN%h+T3jQywq&7`P|Cl-|bAk9eEpOCV|6a$^C9|SPg@G;e& z1s@_o1mgt^g8P?o8{;~4`gFPxr+}{Bo9<;g0YPvwVz!;4@H`0Z*^_;G-LL_oLjCe( z5ww}678Zes*E3zh8w4fElE=ivu%11Co@fWeFay~P7fEgY{87^)zwidwgdy!M*c#k02zgJF7-3W@~yAQhS<>{MJbj>-92)>4oIoF=~=76Gr0 z90J9s9BYyWu)(HF3tSKg)*qb{DE5S9$4f1rN?a@r%RD!xszu&FEr1}gd;BJyl?2|c zR~jx__3axUP!-yCk2scd?KjaLZ#i^@&Za%P5_=)<>eMBxyDA!~$vok7^S;n5vOxkX ztS*V8N|BS3g+U*ti}Xg`=x0>6PJFiaz98aYDldWQN9G@H=84JF!ar5J0#j zt#9EmoE{`55?2+ri4cefyg-!im-&r?X-7`F>=TgG(9)^~c~4AEa3$#Zw)+PLuB)o9 zMsLfAa$ZwkuZ1P&UW>psLrH*Piy9IwND;_BZ}9zpUb#<3q3Npp^of;hFGWRP@|wQk zygbgtk zh@i$NTrXN!6 zFFGkhL&F%raDM(Isb(hyDmqs;&SCk;G(?mX>Bx6S6@=Tl=<~ zWuU`-TQ2?GUn7v}$H0`3w%jJoN0@n_CA3(!#_<)xL$gxXMXNg@2 z;G5_n069YAH@mWtLVjllR@ zE`DYE(XN28G26~BU;2^ui?2>?M_xJ!&cp3>BT0a}cZXkF1_&d8iNvIG?%chG7x0DE z!F$j*IvS4msiqKBSW{E87CjGCcp|33oRZkSf7h-mY!(0rryuV&l1vYHB-kig$I8bS z1<_gWOn?e1U|O3Nl>XHHHI zqT187HeG^f4W1{f=|X|^M$qv;j6rSRL*oEuhKS?9cw@NFA3x#nyX%eb06hTI_?B!4 zdt)$ELcHsqWM^LlyJHU9mn{~bzu@@Uvs`N`atuqV?5Y7|K#==_D!_h^hg!9J&z_4B zVs~!dtb*YD1yUBz&{hqb@9Kv+WA#U2q9Aq|h_J!r?KnHP`F#D_(_><79fodH8P-qW z-XAnE<*?qqy7KEr%#<~hd{iOqU?%r( zPf*3``x9eLHCHtfLmoDzZFeCPX&QNwDanr?)7seBY&qz>7VS1TmJNUeYbjVwKaiGq zFU3B%gKB7oR1{>MT6keud3l+@moV~3F(Lr9-5%IAgA#Ot#b<7Qz7nYywwHo^h?Hxw z9atdn4V05@dTrelZ!J~T^e$IDC2M%2(oXN(ySEnp1gC#v=YVL;0D<@oE&mMEo-Ol~ zWMpI%^;z-S=Lp3Va3W;mZhb`}5_*C@j+gg7L=;_wK?Mj`V&=KEQ;&P8xM3AVmAp@o zH^jB$xUzH=Y`h3Aon;^YF=~aO)0y|tZI1(xf@o}Kv;e&);eB~D#9`3krddRN0v{Y#8Rtl(wN))KRi3w(SNEg^tMgl%S>_o@8 z2ALRA_*UR$*jE>aU9m%n6%c`)j0!0D8D%yK4`U7+q{q}xCNyd#$!+LTusMla51D-s zmPkmIbB5{Svp{e`RG8&C)iF;!>Cy|Yaa|#U&K*y=^L!H5dD+asXS?azYj@nNer*GDM z2ZK-4YqW*L3VQKkW^AMc{fMn!zAbh=+OETfMn+CcbAJxe4ui`DpTr1}4z|Yf*sN`l zX#SW8odgx1Q0oH&W=PmwbXcCfx}YLJ!9;=u-3;oi26rjk^#Sa6I9dY;UA`ZT&->NX zsL063Bm>~exKC`!FDO8Xv-db2U_RvKuUt|YAfI-3?&@NX$kmLKYW3(`PQOx_Y*JtO^w|UL(fORO+|d| zup*;EBSulJ((VmR&C7WF-bzRa;%r0gwCoGb*F}C+C0hi%kSJiH;hXEc=qt%zQBY(F zo&*~h2A9$qp1|Ok1=1vaLmlhG-h**r0GtRslZmJxdmDgYHn6eXfO(1_LXb%0x*Jj5 zn)LCq;ErY3zkmN08Al3sHf?l$oZGpyb#Uq^BeS8`GXa+aQz~BYd3u!4J#Z>lz}_q` zFJJ8Zg8{&NFP?AxV+g+lXP}y3qt_yxlUKS94c5!4?{C@h*aRRKIrIjB%fnqg3xGUu zJV`zhH(Q0TgJO0QcNGXhsp%c4BV3gpKEs}}YiAxcAEbNI)Sag}JN9J_>>pqY>6B7V zc3H%7!b~W^gKnq>mSz*kFhsiN4Pg8-b5Gv%KkQ@e1%OAJ6hJw5y z>Na*369NOj`>W~Jua9$1Pb*0|QlgoLsNTvy3-P$TCxe<3m)G@RG_{rrO{;CumLygp|%uHX{4#6~?gkGS1 z7v&x(6xu(0@q20+=$}l$)Jwhz))?a0v44f@5x+i2HN~*D*h>LwP6ClO0AjEPa?+oq zm_(5F3{CzmU5kL$F%*4JcO3W&NUXt+AMe0Dq@CJqWslvH`u4+zI%JeudH*x#&V`Z; z{^0{N9zZuUiuKRF3*`|=^sr{>jxAwB!IYO1`c$xKBfy~q7EKMZN8}VVIX=P(usNuCJD`8yj4NPu`2p!C~@z@WY#svtR^63Vf*G z^DUrlgP<{D0!=AQ57yrL=b%hMY0Qzd)$CRjILaLeM<4P8SQogADHtLc07O(df1dmJ zL%C337HQYefKyZRLrH@OTY^7-en?yo9m)I4wKLF2Ccc%01959U(QPsO^tB|dk{8@G z@qxQ*ht>}g{Sw8M5QNB#sMf+icG1s2#~27|C_$O%3xi(2eyuTj6haIHY$f;jA|puj zn*O`M^*?;bN5px!=OC^j8Y{kjK<0{zj34Q#}DD!1P!f!V_(GOd{(yLc80qOc7s7qMrIp-(G{@2e2yCCMW*tv z;E}k2;P9tAVPZl5RU*UI>xqktFC2DQBjxao5Rk8Be;q5}3&(PUy$A)DCS_!icDmu? z$9j|o0_2Et?dfWzgzTUM%${m1izW%iihuw9MZQ?R15u2Qg-=cqr0&?*Seg;Dm5Rd3 zTx#c#f34eM{m|5(@uFTSPo1=xFZosg)0g950sfZRjo$R}8~QZu?iUu}oxiSRDgOVT zM?!!2f7UyM7L1Hi{r~jkNP31mlyRa)X8d7XUt4Qh;Y&5#`h*?C#c2LB)KU{f_Ds$% zz`#I^eh?2ou|eAy5Q{5R-7*_%20W)PJhEt+;BW~eFB(n45&YvnZjNq(a2hJsac>8qmHIu293Ei`+ojYMU3o zj=>?owCrz^AlWP4y<(y{5H-s{z9^htw&G+T0fwCl^4HrZ)P-|EWbDuJ-1tO9(_ zblpMh05hGMOh{0|9f7i-g#0%dEo;2AcepomB&c~Y=cXWv}+hVLC669B};OP2(#X->|FPftxL8yaqbtRV^|3!G2LvqhNeG2)@_<|YM= z+r-3#fucDDgXHtW0-9I?E27O9# zaWQcY*=mF9yFp+C&_8hQSpx%epuPe=bw@|heMYYW5VB;j0=Xydv>69y~qHBZFAL zYLwN*M1Z?mWHBb(&lQNJT_5KW3Lbw3RLefz>QxBBc8%Z?qb5?soR@rt_Wd9l^f zKveQY|(GTFZ*cO25VIOBNRWSeJMSE4CGkn__|o z_4*O85*%j3eo`2Tet?+Eckf;ge+yK0&UwKBuXYjMUiC`+BU)i zY~kho17iu)-@&*O^7DPt41&UgReeBkUU{1mbYyk+ISi}NI0Hj$e3Mg!9I64~My(7~YC@W;D(>II%FS->m*vL^49$|gq z;bOB2yBJ{#TLF3n)@zK!0S)V5pEm5TLMdxjbhFLIWmo{movBzOsX2zs1=;FBhvv`OKlxWmqq6&fB0_roc$bj6n7-Ki^j(ix<0sPc#L|gw1{g{Q=(L z5n|oMurm-eTya~4g##D2ICMUzLi`bBAE8JKK@s{gRpx?oneCSY=wx80S%aeI0p}vx zZKLt!>$9_yM*EFlXUrRLvLl_7dv?Iv+$uPO0Q-X#d zC@afTTU%=wh0(1w6yoRyIf7PC5Sbo3osNYCJM8KeclTg03-BTY0R@9KHifP&=vuy5 zG?pq>x6~<%A(wlQi>@Vs;t!9Ed?s~RQ1FK9NNcEtrKQVfpli@$JmwL3c-=1rl!F|n zFunEuIuL|)w`oKklD{~D`OfXzwXg-@-iTESy9TbF?$=kv@1ujmXORMEe0dK#2N?9i zR#sA48vgZPDM-LKWA5l0{(CM!Jt&VegG(5&KLC0ggFpD%W6H|@^K)|{Mum`O#_)lj zQK0U+p{aAQ2}s*PKq1pY;2x22@8KfX{tT>>R*;i>@Z{;!mq_~f7HRt)6L20DSU0oT z5=ds-S?R2o?#9Q9xRs%iIk0i#ZR^h%cH)A!4HU8kLNy!vc??4tJxkCZULya3D_7!-%UtpHu1vDkx-@SYH$RN|#H$F-DVwiwB@g6ptM|^#KHSUjx+?|-1if0b? z_8-W|q+9po0SSqVLm!iJomR3=KkY;o!>`uX*NekA61)8R_QQuCD2@txbzF-`A@|S# zA?up|&$JVU{t*heB=MC&IJ};_>*8-0Qe z=-_>Iwepx8%Iwd{$qRN1C_48LG_%*>qC?s;!@j^g6(=|MJ1Dj#SCNA)i7mb~nye(~ zyV%}QG`la660s-9D~Lx1kj{lLU<;D2XB7U=1H_iXHv~)57f_ux4}5?{+M%aT6aa+H z%FdQ!d0&DAaLMhxejJfmuWeB5DB$AcgtzYoL5;>&RZY!#>cVS}N_jInUEVJPSY zf+7!DG5jmMe6lvnrL0_BSat-V7zL)f2lu7m4Jy3yOSkT9TQ3uy(EcHGl&Qae2aEyG z4ZgeQZ%1EY{vW@{b+~`@^!0zr55h8IJ2TQ|cDJCY$P&2ryYVIt4pCHpTusux>&yl3 zT9PZV9pKkwq^zf->-#wb*FW;##4OC1k$>jB{-HO|TLenBfc!Oi;@{%%Ps1HMc92sT zNKPj+_<82_N=R&A&B#p8{B|xR?Zm5Xw-vXNBLJu<;CKNBR6RV3HQ2wG{>LH*GWNow zQC2V&bJ%3RSG!85iXXJB`t;?NF7Er<<(_6czFu=?r{L{Ojekb1TN&fTg2omP#hcpR z*5GQ4u!z@e*KI$#K3z9tOiQKt`tr)}@ui+uHY1$w9t!*{(ZMcBE;&=>$A{!6U2;Yb z4MoA?1TPfv;(y(M?aB_Gl#G{KpVr4P)cd9;)r3nxyH0SE*>}N-fAOR$U>ccQLRnx( z$tK-EBoku`v&cX;vkD2QrFsEUWF9G#Y?u|}JRi_7s$wyP8NApA94Ks2aQ)rfeIZ7h9Xd1K&|YH+i@ z86Qsv=nrH;O(6vxlx#r2S~3JtQ94-i;_4;}mc$R48riuT3?VLCi;x{Lj6RW$aXn(q zTbP{$Hen%}F^V{07STpNw`kEYdd+v`pz!ho@E#Q|L=Ksm_V&0=IE4#Jz6fsTI)dejgS+YaG8O&&FYXh57 zt1WHQ4y(#TGW|u|2H@|eM>|-+xtbLbR{dCl#FGy***$I+cbR_MuhP)clFMTxI91*C z+a**5snK`$Y-HV6*}}XOG_8+`YO4a-mZBCTbvlB@ob`|Rcj?2zHLDTP<3(=18b$S zLV>HBbc%`8Pilsyo*wIvsQR<4LdtX9*~FrQn3X3e2+H~8mNa^Bc*QGa;OGE&^Sm7f zfTY8pRWCMS5n5VwoJ`4t)?Mp3UYA;3Vh8SIED2sE}Z%=4`qCN@aHo7 zkKh%XH|3Mdoqq21YDm}x7H1wK4MRMxz~(R6P=J(`T2VJ`FM!yNX%?4 zuuC%rY>0^+{FG}>{o@zt_KCp?7bfmovUY&(kQ|gnIP~Wi+ogVaX>bn(LW}LkK?)?! zPztceK0Q)h4}<^>n>r%TI(m|&?dR*{{ z1xwqH(sif4zPagDL})CCdgf?QE`NC;%w-OK^awT_mpO`F=FIF8vW~zHoF4YI|5%+ ziJ?N^XgIY9ZU4HgtTsp7q=G^gnXsqm!4bdv-3~(J+hb73h+ypbdPW!o4(v?kAiD%< zucrfo0M~^YMj($xEv`aqfCV=Iquy<=a$HZtc!M4se$N;l3L7tPQ`6+9lr?0k12}k> zKY_VtqTj6+*>!V55Ti0@MAwBIBF<7$B_qty3_*0NLpJOi8ang1X89m^sjBvNPLyc% zxb508@$n6j*YTywiTj3q-Q7h1_2KsUdE682mEht*;6%KkXS1(fPa+Ev&$9IMA^dia z9H19i6S8;A4BpDi?T6~zkKTZoP2o`T?MmDPPVQ5tju5d3fTR?3*X0KZ<^SS^bHS8B z{$-u<*9cbu#3T52%D3^})v$4MI7^f9(;mfYR1N1Tw6@TBK!Wc4H@VcmB6;8dwK*fm z6EFg6eox4)TyTA!mv;mfeK8~eR0T~5lc)N9FhYo6(qit+}voSqH0)C zKpBxaTD#Q0fS6#D=~9LOCJKl zhV+AgL4y9Q+>+J-uxt|pmcsHh`}FiQD?fiUDo(2QeW~X~MfH#XHf-8dANhXz_isha zNRnd-(3z1FD0-3;M=&u$&J6+FSpJx?0}R%L;*+P?62R`{JQO0bfbulCbSVh_L@E#W znL;EHVsk~!fl{Ujrz_5`C@#jsG{fUb&No5g=eV|x$+y&h1f%uD-ihx6MaZIcXU~6J zI}W|_AdolV3ssSI3G)W*+=5@m8DFGd z*?@|Rs=>v@Me(@Hp&rS-4gm=!1g$CQEeImf(eXnf1k72F?eB5*YGp^qCS0N(pC+kl z34}jT%fiQS7=g8L7Qz4sl3HX?g>&A*&5&ep{EQL~$iRaV4hWV982bq|0ks zd#wg1Dy&R37Xncq!IV6BIm4+8oE}1`Tc9IB9DD&5=8*H1D>V?^;p_{-7BdAB z5u8FR9uC624=MyGH9|F_nSoYFPC{Aw*X=+i=J)K~+l)auuhr#Qa;Ouz1r%yxta*Gq zF-wdFT|cpoB_7)N1}b)BBlfy8{gWINA%tA8(_kGTJ$zQ?cYq|>rgN^~2lfywb4NgR z5)=jwSLNp_jIuEJtD(`wStPLC-HNt1XFkl|u>5LY7Z8)~XJMy=((tX0f^y-#{{X2G$b~$If8>g}Gh;`&! z=@I%zJ3*p9K_2JZG{cGljh?W4Ae&SH$H|L>u^Y+#(evl52q;wulg0I%yZD{x85jl@ zH0HhJ6QmvX{TmrUkBOsrD$)K4FPN`vl22j*$B*E`2}yu8G?-hegSA36$7JuGJ*19f zBMzbufV~HfGY)*ohrQ+)e}!d(yhAKu&k*DnQE_p9pnWv|eS?GkfCuP}$*>v9u_CgL zz>XckljV!du*)0){zeUnB1HirJSqGu?YEo!0MY_L;UkL`_s;!^G|eh3nJ_23C#KmP-Q9B!oIpx|)f@&pf5e-VeNV&TZ$ANC!8QnjdqA^B4Ba6c zgvi-Kpl2{z=(NfIwyQ&1)zt%ncuB6i8iPasNRNbEh z2C<54`{|j1G?rQB;K3Bc6fWzF;Kvjg@r7UqfYb)uF$25Yb2a&|;oORtfhHOzbY#SS z(vhW;L>zIDX-GOC<^epy_0?tf3Ax6hsb=iZi97}Pv~WjG(c^CsG&m3;?ai4jq-ULS z0lp#JD%x3Pu+UiDARNAd1#3pt!-7%cWE}NNm$nm}jg6HIVhN2<03sTu9D-WVd=Mud zs0UR9BN#UpkU3CUoTKI5;aUimu~{$nTx)L@^f9>2R9cW$(~B&iyL z;yVD3^cQwkq>qP#*%r>97UuLL+_20Tyto*eUmX($;W-1w6E_Z9VXMdw%Uf0!M)%{y zlf4DwT6(}$;10QF^Q#{dez6@o#R>iE%F^(B+TXgOE$?|{;_f!Iq}TNSC_`}X*?3CX z>3hQloZ`X&83^?t#!coz0p4M#-T6%nfph)A{AsK@O~e@t6l01x9>M)$TV3zs(2VrA z&szWA_h>G;PQ!DhmTVS;V`I_i08BPRgx2;@<)*4i(y6G**MCm27uEC*QpM zLnA+07-*6+uP@K>Xd#@MBeta8h|d4*J+-LlY9DuXdgzhIoh0oLvX;7X$BE?I-SeF))TC%#XkGa+H9w;}8RTxD28Gp2K;(bUL)iA; z10ZkyS1>*LKN9Qz-M?g8)VmDtD8@Kedh%i%G_aq5@{`lk*YQQ~7N%4a<4EPUbS_KGxLgO*z z9@uzEX@&|43Rix${D`}?TmT+d9j*WzGPDlrwpFmQ{01$p#$8D`cr%#F!)L{@p=biS z;#rK!Aj^cH5&e&e9Ar{{wP4zD9M2I98#Xx=07P_$1K% zkRxx>@gYI-A*-(Zovg3X%e9+E1`r@EmR*d`0$8iiSKG*4%OH!tkbd; zgSA3PtDukkaJ~R(bs&^j1*?{Wwj#$mlF&!z+zgf1Dp-Y^f(upN1d$3AF9wt`7M5tV z7|3gr&sA-BtP4UI1P?jg5EeEVR^r?=()^OQ9p!#4W!JS;P>`CIc}oT09wEBH*lTr} z#yY4V*+LKvfXPAt5-IEzx9};dlx;`Lxezp1$a?o)ZvqktdIlP3VGj4Ih3K&cY6m$w z2nfp$oM^tXAQPjo&R=z2PG#JsSvD)5@zYZ z0j2Y@S^0{D-rTPXv`H-8IL6H!-4-xk4dlZ#Ue5WWpiffBhad*vLuGevo(jJyGH(X< z69*@5h1NAOF@a8(mOKYiiH5Ai-*wlfhc^)KFHYftRUSIlQQ2)RzSt5MUe8|O_W;zv z%-!eFHKEWdorx13^Kt#iHUAmB!D~y!3m_-@6?^;kA*!^Tt+T!lst-rBuJ=ry=Xi%mIhz0;f z*l09ki}nBd6$%{52S6PZ!I;Rb`L$U`xqLH5q$&ZViA$Y0|4F;7q7r~>=@O%Nvd`)Y zNBmCKW9K496PyLUH1>J%D(-eAeb!2vfrKRLe-edk>_neXe>HE(&v zVWjW5SuF#?g~&=kTd5ti*Vm8}l{DkFKAd$%Hf`!n!bFg|V$sfVD7u0p$T zxULb%f9Z+y9&9lgrv&ImT5C9SgWOKp>OuwV6Uk@~(9EUa+rdT<0)un!`G7YV{m0p- zF>V^)cPnY$idjv?$S$Vbi3tlMU>Gc`L@h)gBQX9cBmim`<{QsKCF{dR16I0AKBtV& zu|UcZ#IoYv>Y<&QT3Qm36hS9DOv-Iz46gDoW(l%M*b5{YeTfD zV6PaLc?yqz(%1`r#vF4SXy8>b9Rvd{f@A(D_G}tWQ-Y*2KnuVW{GUz}Gk$6PyY}o+ zK~ITcfdK6Ae7kOaEO#!Ku#S>-C60wdH$dtO6a(81o9Mz+C-5eyl?lA$~@D z$OUMO34R3$aE>6?P=JGQbG@v%Ij^;-N+i?M)6;wW8`})O_OBVgq-MYcf(?O{$jCBs z42eQ>lvG_7fNsbBs&#l%7^y6F?7xv;y|4>AMc4L?3z&N19Y-HSPF)4g)D4O98YLe) z@y*9O85j+xuo6+3czfz*a9_*!1egAjY=;Jn@E|xxr{p6JA|bXTY&$dbEAaE&HoNuR zKnjFcF~g_gLb)NxsD?6T4~~==ztmn@R$_XfWji zO|hQrcR)m_f`k}3aA30hMuZr?i%{<%m~^A`7XX-oV4sa$%Rm7wMl2f$opg@P0*|l= ze>WpV3GCg=1eH+5%j}(M znn-EoXsM`8L#P~`zsJk=&+qr|@Av0S`hGv3_vdvyug~6)C>JNE-Au4whp9!6Gyduq zPtYhX2@Q)3JXssnCqqsBoKIo(!>8g|0ovTA0%6UrD~Y(Vsbh<4+qO*P<2 zw!uw}qYVx7Vf?4}J%#;@jwqRdJk`UH5dam0Ee+ou9Bu8~^WZnQcg5{XrxG2vfpbbA zPm?)&AQ%p~RyPHwPSn{XJk$DY_qE)KJiDp3FdHxJ0)v1%x~lN;6@|8 zdAdnV3>y4PhyAo&LirsutF9vC0Th3M_R(W~C~_1YE8W_jW>LTg;(VgR@NZZ!+Pkvc zO;(v6i&aCNJ)%T2W@t;KN&nzHL7;&9L@igMS$md<78Ra#z{Q}kJJE3pbHeQtU4RUS z7Hz{xn^fZvf@De%o#HtnoKe=6ijM(%NI;4m?$nzm8N(M`0&7#Exot}|tGP|4>bq^x(1 z`c(vT_)VN13{{SUO3nvQO?}LWEqRU7foRE#fBIRR>EMpa4YMWX?#F4{#0|rYyVcGS zU5feY)sL<7?Q~@Dg*QtsyY66TCrVa;&~v}N6t^CUO?tiOo&nujkL+gkt`}F1Kj^2| zo4mL#APHG>5}-3U9QgFXrq;9s?vAx`@Pa##YLGaOKwdq^f$BiiF&!NIeB3{oii43c*Q zh-3*In>u7)R>Zap0Mqe0v$I;DJg~WlPWZ0=M8zW$|EK@pPSF6YQ%DvE?W2o=r2*x& zl?ZDvbjfK3;3SH@Ww`HLr~^6|?5q3~$I(MjQ4q2p{FY^U5mYvu)aZ@8-(!8pTAr^bhelRZ!YwI401BgV}onv4F zB^KJ@CePG!B1}POs=58QFvU{TDPQE}7me{}{AC1>W~i-j1IreQhQomS))l7aPzJ6h zHL@ucS?o$L0Ki#iyB8N1i$NwPCg$2iiK;jDsatCPZCys z_dRm>a19itd~H!>B1*{3&OZKCW)uM1ZpJ0C01KW4=POKsL|UShnaZp{u3I-a!ZyNc zRgV?@QHE!le<;Q056!~D!ZXepLUcj0$|S%aq-1)+hl~w)xx6AHAh}Gd_jb;a8(R@! z+<_?dB((`~fh3(P0!3F`owI`rZpAH?ykqJy7~}5nq&4LR6zgj0KRBs8GnO_#v&4zO zk)|t-5BOs!VokB^P|N|vb`lICrUB|4Ttv1=c|h?5J8fyHDLFB#S?M-jd@3Mvnwpv$ ziAbZKB>}-JvQTCS0E@e27z+#w1fTYlcmAOM{mJHT5aLcEgP~oD&)ARl=m56$LNSO3 zxGx6_2e%ah1o8VR8ouwxGbh=>kLv1jSWzU=pPMOPn@%ADxP=ST?`^_MRSgFsoHxBd zRvMHtq?$-XCATq;?=2Qrwjxypw)G$$${bisj;X|=bNCa9cg61bcL<3n7De>PWy1QT z&V=bq&;=7tKDrRPNFQ90;K(A?!x1mT0{rbhux(dJL`CI<SgZ#;`0}VR;1T@6{3zHzmZ*;$l*qprlEv)C z7%OT<0e65R0{s`M0d-qK*fOwn7v~+77`sItg_j{Vh^hV0$B*sPJ2lkRg#>^al4DQ9 zz`A^e%}^A4Z79kiBm|24KUD<>wO|`P0P93EP*9-8;m;AUXv&>}&U|gt!k!0Zd2D?3>VvoExLW!cRwE4z4H3{B zj)*7#FS`Sqml8nJbwj!aPH>Urw6fFlM|dn|7r4VQx#HoEpJuj=%|7&5#6VpyDstnh zE!*{8rfE3EI%ns5IyY~qW>J}Qa*+yvd0`Ambm6uE%GSQWPEBRjwi*DZB_w;VE^%Fm3$6L3P(a|~I zHq+=%#>VC`d}L{Fer@y?d;J-# z8G85LJ@4BnFlQ5r#vmAyS6f}34XxscCljF=1udDCD4CrQ(H4H!73@G*TG6pyLw%c$ z#)7{EXI2LO>ql)s4#o5622H73Yq%gW@ZB$~s~d;ntE0{Mc4_IOvItDJ_^Jl+gCPE& zDb|9nSF|v_F5mOPm@{d)4}4hvR#I+WI@Vt9rK!0RY(U@GI088r`}TJXe!n!}%_97CRpH}=T#TWzjf(@&v3<3R zsVAkAR1x~AefksH9P^m2-%;T{=N?;J>jOi;VUSm~FeL84(I!M7b)}l!jkh%DzToul z9)G*+$}ZJ7?n;BN03%R(R)bY4I~8##0d|(X4RqxNK(g@ zYqh$7N7$dxq$lYX)aEJ|l1~CeGz>&WP!{l@M3livwR=n_p1E(~#3vhlWri%Hx@7F}gM?GvoV+jl?u2mskNQLEg&iKIXH7%e!i#O9dm zaWi;#huD%C+f)>S(0Lq1U?}q^@MB2R+^;}i2h12mN0X%)qhkkx>Fueh0ik1se1~=W z(%#;Z48lAQ4F$~4)%HxdOFnr;RYaQjf_a9f*PPSuY%ijrenyU($q^TtUO#=8%Y!IQ z`Jh}$MAR9Cup*!{_%8iEg|e>R&D~v{;fmH7Gc$r=n;bZKsmp8swp(1SRHcWlY54RR zmxzALiniQ?g=YtplL*WiwdCzWGAjVJ_0pL#2rt;MfkqyC`O@rx{7J@DZ^K1tUGb38 zM~|edZ$%=@PO=+Mii}J+U2^#*^(Th#lgpyYQyFwc4h6-=i1q^pE_vFZm~aru3lZd~ zv*2+WMX!cAntiY0H}ft#maF!OK|EWf&609=e5dK83!nJVc1h7|0}h z0`J2^t0C+-f{RF6XV^K}D!QVQLxLg}GD)6Lw!N?xVFeVuIhZJb z%a_Y~L02J%yh3_^&g7kvl7;SQ5c_Q1VR;vd3^B|E5@7;j&0mc3iCVXIt-!}H=m+PO zh@}oWk!bc9t#z5((ZrtedHY)kwG28Ee_B_FLE##>cNJ}DsYUxDZ@D3Dj{|je(E^5q z_rPn>r34|?mjMk4Y!1qZF;3^RIFk6H_fS`&!5ze4gtM)DgA(^W@}YB;^)JVO6W2@l z48tcccnHSGp*?V54L?{hz=!XtL{BWPTT1Ebzxy+!1P%mYVFPEE$!_G02TCm z+{u_?0h=zRY5eMvuB=G4E#fRr{bV%XK@ws?1}f6Pt(srz*S3Bd*#u2XvWYGiS$s%Y z=_|!cvFyt30W#8nhPk@BW;f4aDGbTjD=(!WVOAlbsGy#~YuDgQVQRvZrY|ECXyvn- z93mvsEo}MNkN2x85P>Ak3D>Eo^dqOcF^8`(7{hrEgQF{riEQ?Gr9v8rfPkonvuK=4 zcxglP1tyOkCV87yr0rFNRN(rFJ@)KtVPzSA$!zPAF{_FP zR`0Ea?;y^kFwUlVNK&XZOrOfuh9v>{YU(v=MrQ#ozYLY^+PHJx z>-87c^V3ke$cv}MQpM^ZSC6MUkbFmF_`Am(%8W}?WC%(u~2A?A0!#-EZpkjafOw{IarXazgQg-hX+A@dm)R-+)uUdn@0Jzh4Ll)-CVh z3;!o9|9}3UnImRSnaTcuv*N_y?n58-!)Uxsu=w0ni6EFFvX_ny$Z^1Lw8-FV@mVuq#7^my|n-~1b71bT7+ literal 0 HcmV?d00001 diff --git a/docs/images/device_pin_flowchart.svg b/docs/images/device_pin_flowchart.svg new file mode 100644 index 0000000..075dcc9 --- /dev/null +++ b/docs/images/device_pin_flowchart.svg @@ -0,0 +1,66 @@ + + + + + + +device_pins + + +constructor + +LED(pin_spec, ..., +pin_factory=None) + + +pin_factory_kwarg + +pin_factory == None? + + +constructor->pin_factory_kwarg + + + + +default_factory + +self.pin_factory = Device.pin_factory + + +pin_factory_kwarg->default_factory + + +yes + + +override_factory + +self.pin_factory = pin_factory + + +pin_factory_kwarg->override_factory + + +no + + +factory_pin + +self.pin = self.pin_factory.pin(pin_spec) + + +default_factory->factory_pin + + + + +override_factory->factory_pin + + + + + diff --git a/docs/images/raspi-config.png b/docs/images/raspi-config.png index 7880adb81a39b1a9e92592a924eebe47567cac6e..bf34fcf5963309f18ecea10edcb24e638c32eada 100644 GIT binary patch literal 37065 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 Of8xS2LZt%QKK~1omOgL* literal 33392 zcmce-1$^6XzNecuO&VrqPQ%R9Ff%hd%*@z8!_3UwFhj%4%*@Q3b^o(-&&-{(v%B}6 z-Ct};AK8&)+0y&y`MwI3lM#i5!h!+;0f7}46H)*H`LqjsrbB!N&IxW8`ZEGIkQ5aH z`S|mf-Ch(2oC9eqrtSa&0*(CV`3WR79RoP?tE0HI@Yk(RP*BtqEMRM*ARq)F;zImN zuFIzxZfeK_*aIdmwao;CIEc}T!d=*?!oNYM%-ccWCpD(rb6hPn>s2Z=qRb1vnO_yF zR?I7)PPr>-Ry4jB=i>atp=2Y1_#_a!c6xpR5BCXjSYFtZFKU8#h^&@tBjahD>p}{N z`dl8VhcFOfz)n}26}WPc?>pHnH|QdpI0J-wOc)rIg_>nI9g{73ju z)%=>6=c_G$Y_QnD9&e%2!wg^WUh2zba`(u@EZaZ;weDqJ@i-BPhH*kRYT6 z6V{gKWXw?^2-oVtyUP6@eow2#Cyn4dr#WK`S&-{lo243&%D+SJFF-4eOtsMx?f;ZG zfKF@Nd7#Qh)6u_X4@4Mt8^>W6#f&0*5l@Z-bAq+86QUObMLhc&YBjoTp5?RbEm$%9 zGzTvT;bk9PwuMQ50^d`^a*F)Zq+3)>5lip>;y3<*ZyG}JwIASD6N8t1AClEH}~uM#yY^-qhP9`=g)TU;AOlqv;-Csfvii1Ee{QSf68F` z(GFb9$%F-o5R{4fV7i$D2}$HlHq&Y*pLkSGC#{?A2;F!3cg)yAi+#~w#zSAqR|vL} zneVpMB1@VhQP7LJM}I(+&>#Hnj>?@onW1EJ#BnhDvG&d3n9(@-GB~g{`_>$HCGI`L z&6!9DwZ`X7@+`_^4uTNp<`yOUg!xD)(mM2{TFa3c^^tEMEX)a$M8hl$LE!7_(;?;_ z`nV$o+39=Laq#Fg6Q|SG#Hmp7Ra0Hj^4iqkM5wlRkow!Jo{>a2$3GQyFauQWnbfvlP_QS+}#Fq z+c(pkPdjEx%bo^@Bej^5vwWl+6ax_aVD0y`L*!oGhDtar)qVt*BVx`*{c0NFHAWDC z*x7m8Th(3A-I;|T43FY~Xtpq4t0K5m5x9S*LUi2LrbHwRj8+!?Z7=G)p*~lSF18$= zyiNG%uUI9!i2>XS*z=LrC%QeKm_DO6GyEG9ld?{)(Y3eQ#esPI)c|dKg|q=er6)rW!W-yx?>!BzpbMS4QJRH83|vX<6L2Ir4xcYz=fB)ESA6iz$w_n zBcFV!v12nV?1q7hJj*WM#mO>v&}LNozBg*R`4;hrv%^Qow083Zg3{rB^?Xg zF|d{&m~Juv-{YCF?i^j_K(xov|7_rCay#I5T!kZ(w}-S-JT{c<0u3Vyq5q97kuzo- zl_{j+RqoBdIS9f<{YYH6ko!g8tdqs(;ZqO{OlUReW5sm6%N$F)RLIe&s@~`A8Mwnk zj^nC>^wg~yrh0z#IyCJew6c&H%i=-%2*<#Xa<4~|5 z9+%qf{3OLv#LnFyi)N~l#RYt5BZlP=X0noyu*j*z$Tgg#GIvZ*RDfArAGc)YeF_?3 zpC}ZAu5&|iytgiyGrA~!1|+h5JpHlHg$A_`hsCRI6iqL|@vGkCDcC$EffPhed5!7IZ=Lgbap~E3i9}E zfb^NLVqEY`=n#zCN?{Btyn<{!hI@peG4DK@&uDFEHj?dX9_GseO=U}<`HwXMn^GtR z2eE8oN>Z_KSqF)RSTo+DXiRl4d7N(ZNE%j~1gIX$tLfeW#H<~;-Y=Mm8!s&^EXV0O$ZcpyCdysEC$XHv+ z5xC8_h8^3*`^RO?U^p`a9Ln`Fp@#14MFt3Ed-gLdVIO)>I&S=9Nuwx?J{GQc{of)8 zaG+AWVCyj>_3fTh3GWF(L_VaScI5 zYsId~n)_325-WeQI%=o3G0hV`UE*uY_JQ@Y-C7K)v(XI9+aIBj?ExEj3eshZx-=UL zd{lc4I6@dEv?N-YEdc{Hk8TjEh`w0lL*yT>TyL@JJY;*FmKy@ZxnO;X-oxNM;lgx+ zOgV&80zCjz!~(t8J6EgYXjtRsk3PGM(@^Jop?PAm&YTwbk+%zmgJU5KmBS*8ER17c zDwYrx`XTqW%-E#hFCs#+{t*=?s$jL|_mGh;m2w0_qHPLRQ%tY`DmRMMS%ihMaUSy~ z^#T{PGQg?DWeW(49(HZha3?3avh`R!785~@wYeM)5&{HazOo%%FSm=sS+$gm-uK({ zE^O1lc=m1t1I+Qlylh+%Tq(UwGln#@{36~LN&OPyhw~91&y<$`dFgrr67S6d??axgmQXxC<{&b1Q%5s{MMDD!V}|G*;mj zw_-TAA8yg4jw7G}D=Hou`MiA67g9n$vc(LmokS)oC_GueCi}L(016$BPYLsI3C22) z1U+()Y;YFEc0~ss(hm{S;>&@~Z=-l+BF^yHP9t^AAu)3?taAw!nJ9lyKT!|*Xo+%D7Mtc7N;IY9md*u(>t$My4yi>|7hoBUnVJrx^LN^JjlgB+D7#FL*UK&-xH?tc}w&SBd8qM z)pkLF_(k^lcTbDcj%Lx!!|a8NFg=n>b)WQ82*Iz!`&YM$rrIbqdW&p*zjT&MYl4VD zJ$!}x@b`0^mku8(&>ekeI3wS$)Yn7idb3dZ7#1_zFS&3sSvX@ubs_Ju8Ir|DoKOSjW|ZE7l} z&@9oIKTd-mK`0E3#@^l@93BtGstV5PVmyP3dW4gM!_VDGvC3khGGemIg7IW=aS?a{ z6GM`cl?BgMqY}T%8q2+*Ffj?T>` z0tE$a@^JzsN_FpNC(z4?88Sj3ofU1*&CL~Y)o)`vVzvD^M#J`pxI;l$*6|YIlB?o9 zZchTh&XU&z!GXrGfV9EZf>-$sK5M4{2~L`k`%70jwwV#^tmt=BZ@u}hv{V+kiNO|m zXABj)hXWf{yyi6G;`>-$UWXVE81E&Yw`z$d(bqa zx8?`tsexX8K3GyqUgK-w!EDo0EhHvy_-uTYhx(86S>xP;=$sR8);i=2Li4Z@&+Cac zwD4*yRT;moH()gxlka>`=St#iG9S-Y&yvH5;2@<=Ti|e5+@ss`t@%+zDKb$nrKN=; z=y&9@22%wg><;Tko{j^(bWcxkYKD4#vEG?L;|=Vrfx2t{bd7N5p2t<685&5WUs~w1Ws!}tfw8z5 zOQN0bKbVhTGZ~wvmYp2zEYI%;ZmQVgaopX=3-%6a2K(FAhN!oWgV-;C0Cqc@N(POD zhrbKXN}tqs<}q=j2$pTRrTdPLnq{q}AGQ$s(}`C3cazQbCRH|O2=P~a!Yq3I zkMC$C0uV7GG}v*2q zJ6`p3Gkj^hUngw7%Di2eA(B_yVRBr>d8-J7k3+23s9T%qPz>elt#gQs#j6UJAe@g6W0CFw579y!c@ zx6}MP%L~6@Sg3a==fG$5oziMOiV5cnM75jh0u3KEMyuxpc@P&-VcJ>SCjSoio7|HM;eYoa?cNl z13MrevBlR^%Rll_Wm8-!Zj+c0WuY*po1E|`WCw1U(e)sd-HETJkbK^^CfO`y(mCIb zr+UaM$@k4;bZ%$^1|qTNMf`JO86R@&bZ%3Ki!J~t$U%{Be2^G(;z3Ddr3Mo?oVN>a zj-=$~^OYZmvh7^haS+P7RV~gskux#ohE9jsFWrtRwbKy_8yhXh5+64Eb*MyvO{yMs z1qd_BD5|b`<|d8dWpb(G7M1EI^e3qVqib3r7tT0|QkTbb3L5U#er`$Q5QIj1`@QF( zgE*_JKdG;d^UGwzJ)#(T7u!xe9z->Kp2tkAq%Qq?Pja~YeV8;^at>l~wUOYdp&hi| ze}th3hU78QT0^%PaRT1K(V1x9?yI9WvtSdYkBGJr61?vh2BSRr;4^6`U0vN*WC_1! zvP|r_kLs`q%aH4GBGkO8jW~H%2*Z|I23P^~Oj8#8hpg>C6V94XKp}=db4@hLh}j?>R+x_AptI05>Hq$2oo9Z(-{hDEZOO+pj#xsv_auOa^y$~){8ZN}*8 zS6jdv8Qm7Q&{pt>nhuD8sG6}=?%}nF^e~2+pkzXZ?p^D}7?4kyV+HjJtXukcb#8Bb z=-vboB#ip*mb75$&FbB31C2x|RP@oza_D};P`lvNh=Rh~adnc3FK}74--NNPwZ~>K z(Y^7Dqxy#nyd{qyT;|o8lqO^xrW>Qt0$#wLg9o-jh+xQ2hwEnf4gE)iqO=^KH^=Jh z{c>gc0rl?~*1OwzTm~yL+UJe{#0T#4EWxjhff7lP7NM%TbZbnZsWSvPrJS1yB$Q0! zCzJdOKb90Y%hb1Il%LZ^sv1POuAL|fKO{_4Rllh}uq@=?c(AMcj2H&&Z9YN2=&Lr+ zq*R-}CH5Rx^U+Ku;u4Q}IE%)x)knU9~GHJgNHz0*;pSqk<@U=W1Xt_yfo+uN7##qCg}CDf(a$AUmMx;+9J<( zp&5?7HYX4@kW`OF@0`86)rqNOIHn$VeSZ&bT=u=GqZu>jTej{|kkazUHmv(YJ+-bq zV#6UI^MwFtIfx=~t?tS?XY%K4eei>msE)b4C}gFpAqbC`+KU)fO?IyD$XAWJp4VnH ziM7eMHQgMkmfJmd-fIz~GRxFgvuhVFBNblx(4z~WnQ~>$d2j2+vf-XxrN?}Yjo&=K za;1id&;Gl#PL={ z^pWTqoH2Gc8qar{rCu|rZJ)E%)TZ!871``D_K$Es$)ti4=Kth#N;qH{D=TZ})g`Dt zWS;fO=a&*9Qx*2WTlOfDGzlr+$cFx@ar@-xb`djy zWJpAOk-2^?YI+jmK-Rnh!O$D`V7mpjA@R^qM;60*w6EBF@(pvFJ=5&rzE899Z0zD- zx+EhbBB#T!lNUA5KlbCuWJ>m~)s=;KxH4s$+`&oKD>8a{@X0uVFv3zgyqNX6 z27P;azkgZuheo8uq;RAA8F&c}mkJCK2hIQoO;5tOfvyO8AKi6kW-9Y-($Bq157+9d zL^-VecwTlrIlru9SX9T*LuRuB zz?9#9T-i#QupkCEC6RkPHCEz9I8v$D(aP00s^4EaJyg19aFh?F-1&f!FuJ(Uyz0b6YB(N%%Y<^QL1}$c@Jz-8+)@1CcviAFJ)B%>$@wpxpeZ znfRrP7woT6$#|A_X;kd%zCzbV--K2zjgdPsE!;b=uJ_mzbcx5~HUl)wEgNT|Km^(b zryK3V{V<7Ds>h8nawoZ5X0_#M?S?;U{Lop#+|wL%tRw*!;$3jdrh2d*H1XsAOpNgw>qD(p;-IUcy)bo%&R+BEMbNb@n39ZN#}r< zmUNbf(jb;YU%5Nr&f#9*s*O7x`iXlPWb0nse4tFThKnA=+2r{3)$rOQN5)*tHBO2b)k+DssO4OmKWU%}cMa z@M+F0pEPCpIqO00&-QvBU)m6OjY+SsXLY^3{8Vg-THqdIf8cr<)Fb;%rOcQk64?cV zP0mU0?e|FuSbQPDoweHLeCzZ)88%`^w!QqIakVcQ;R}l zzRz0fr-`}>G(wEJ~Xy}whO|x~D!|app+4`!&O1w9XzG1ExAFqpb$=ZD^l+|9hUw3a- zD^a?VgS7c-L6l-q%}oyjlHEEyW1$N8F%1qZ-j2_`#K>%-JmtF-NCi6VwwDU4wM3~o zP_Z8__X3qE0f@itaA;YHYV+`R<(Z{x4MZ>So`PMnLPx1{F-kAhS2uzmGDfl~Uo;cA zZR_E&i)%i-jHFrdHxJTl>~bG2>0}G0^3M(vsI+Rmb(qh0a@KiuaivVRI2Mmt%v@I| zt^7LIGA?+r89jF&Q3q<%3w_@0n2be+O6fMNR~sc;xYt;0MhPZl4^G3YGpd~dUm1cN z)5T`3_p$hvB52+_bnxAtX*g84jh0^5oz_T{Gi&Er5|#11DRHLPV064>pP0mU5BDNv ze&94GrdQ?6aa?_zE;)@D+4@-Esg7Z9lyht$F$oIqMm%b=xdavnC(dq>ReQf3x- zg6HOmE|jbFjgKo)SExKh?l{(`m%2O#=<3BgrdtD?aL^50MF`5S2FyRd-EgdTJ!dKL6&v!XhOz>LBC!vbA z#Iq+J4UQ3_jv&@$e2nzhklP|Z{NP$cPn@{C#o_6MxO&ZVvwfl$y#0jE=f| zSvmwkst>aR+|^6fO2@k9U`&k)Pw;rkVh=*uHsj%(R{&=kGT9Ncx6*cHJCzKoy+E_! z#a7;1{tG;Ssy>~!swIq~9<{d?htYwN^LnM9uCWy2ZU2m0WCC+l!k0b2OvmZC4QIeC z6HoKVr+hnZ9(loMNizwqg%;+h5>Qa7yk&#SgH=}YO{uxIRr%Xf#Dz9##s=Tt4U{Dd zIzArWdWY9bqnEIj-D$_ghqDHIQP^(#yY155$-=>CilUsHukW&=nwsnDqa7O?TXe2< zZ*Ol~!1zkw?9KJHxe#lFA;l0y#JT3fV)tX1thC3|VfzLCOYlW)=4KS!95OAqTIWAntVM5EmpGb{{Iz@U0@b+yfSB=NHmXb-TTz~A};_<{6( zQYNec_Z8unkQnX@L#LskX>V_Td;L>w?d>$w)U-Nn$%%>gDs(@FIC*{c&q-QZ4Eq{Y zWppr0N|oLEVorF~oi&$cl`6teq!o7Eh375xSBJ9h19jYzEBHNk=B;~P3!_dA1pEm> zBI4`n>f+;3bai!s*cUltUJpSC(^Fnv?&;+m0hh`$w*F6Y zL~>`a@rmcx0S@haggnp)`%FAsTpsh;Z$bJJFa<;yL9jUN^wiX&i;HRxquPfUzf4AK z6+h3u$|@PpKAFiUMFvr;BRuT&yU{Y@5C%dB4vYs8IPy#rI4+l*p^utar85<`m*8cg zjGVp5yaD)I2eUrh`+eiT6O%A7O!f5%m(5KxS9pP?7Geh3IXlZpNqwnUk0}k51I&2! z`fs9Y6E_B}D*Pg_5fqwVKE+m@Yd>&gE8o0K&hI(oXKjqv2!xP%yM4`!emgMCnh`VD zIc74PUz7o77YLDga@&dus%@`9PsMvbX}_au}&SP$R~Ulz!2%vypL#0sX1i;JDlmgg!>$xa?~zcU+tM#Zw{{W!HaDzjASMV*ZVS=%hJXtj&A+wO z5|wo@TyHLQAtDB4`wBE4TJ)W@ibb3yKP8u=GUnaKt9?*;p0T%!AMb~kOxhc&PN@YT zs-GUt7jQ-bo*uBU~m=1ZyMTL|i7afF1jgOa5Tty9(6K-^} zbN0KF6dCu;SrCEZrlw>92&)K$FY-!CN=eg4;c>rnB%%uVf`f6Pv25&(9puCfE1K!( zCum=98%=i`bG8Nq7GQ+QRcu-^A0)U-%7{&w#>;hm)-0#@drW#0HKtIMwAVL6{KRu*_c!&NS$7MMR1 zEliZFON>E*wJ5kq>1TQ_sshh5Y;(k5;Ldn)uej5dyz)uyNv2mr%vH|zh!oc6jMmP& zcN>jXpoRAh39+B^Saq0026HRPED%&3eRNH89%|GBG%z8)1l4?aZbe1o9mI*jaV@2LhYe4~uS^_keYvCZ zZb3A=N_7HZhqobL0(6jv;R$joYM;W&)KjDOLQHn`@}fG2nnAK*yu7?3Lu{XZYnHRsKUD2#%gmtK+ zCLb(Si6-4U+k+Nu2_gzWu-L_%n9Q^5hLo_h)UqkvpAma_^I*q3wpqHKED8>&KXK!U z>(Mc7aPt-#BTkoIU&qSI-f?P~q1ayS9^27w3ib~VQ?jtsTdg!m6kN~QI1kuqQKONQ zkSs1Qv-UD4bRqW4HF#a$Mz{`tZc)Hqm_t-^$`momm1U+?ez~s4Ocj zr_>#r*->>8ma5vh&Cb>=l1=ApBHD#C-s9D8=qw80U7r=M%u>GzKg;KMU@BRU{b^=F zc{LctmI3-ojpRZL_tPb#gDAf>Lo2FxPTsH9r*dx&K_I1VCU@-Q8ADGwH@RE_Ub*^? z5B-vGb93`@0N-cOh!GkZx?ZC~p+v%;AErl$C`Rs^l&q|*xcJrWtxk zhJuuy%{1cTDK*}mRu2oUa)N|0Xz?&w|JrzBYsyubWb|Uo^Qg-mfB5y#-r7bvO#EBZ zs`leAvoNg)n0kg2KxO+ERY77(vg795V10CjyE|8<`HYw6JapOPg?^=|UPJ?B4mzd! z3c5}=)s@w>YOpGCQ|7^DU-(avJ6hV>hK7dteBPrq<<-^ITC_!6p3XmS6p`~#>`SQ<`CnYQy%5d@9% zl%w&S>|Y8u;>s%F7hGwr*7H2zbtg9!zlT;ZTg;CxEpf22vhw~_gnt$7pE~~?@O7=l zDQ;x1UJJ@YTj?gXL(b7;AaQbVR3KG>y8{KuQJJ?ci}VSA%ddC9;>*=?G&$x-S|QKf zes|Iz5H)+zSXwR;gJef!x_%rI=>TZKQgR|mkK*CLL-C}fZ1)8ezXtk51{!O+FcPP= z4c5D2oqDeA9WqkoF_M^16Uz+CgJn-|M?vfiM7c39 zKN~h{jfrqU$pIn0qA&ZjdFXWbmLhHXqTh=PE`EXy<2QT>ADV(nbGb|1=OZ{+^{Aw* zw3#cpICSC3h%Y4KNMHOAD3>$~Rm!kg3&EB7=Qx1?ZhJIMN=H{^ zZizLZ5UaRJrQiquInh{|GC`u?GsXA02Pe}nkU*mRD_;Ivf6IU9bosaF`9JdKe|f`S zT{Hh7p#F!&{7V?U$%X-3cZ5h>e0+RDg0hxYI08~w-~RqSjb;N1#1{g%Vkls!$_%BT zpa6tXQ!}%pv$L~ zvWaUdtSrhWM8a_>&3G{^n(2;LNo$=S4s7+l!rcI?RT1gb)3tS9*Ee}ivyWGT9aPPr zG$hpF8310^jn!0=CRrWHZw23v!2f!FHK{F}=~kuTHQ8sod8t}X{#oxP-Y9#n*7~@# z;P>h5?$-hin6C?yY*b_<9*a3j4?Ss+0wPQgI2;ZJ8XCaTvfN{z))8h=k#rD58CynK zBqIyW>Bw|27R*l9I{kpC2got>j;EFo0t-B_0!43bm4i2BOF9|UFpt~{)GnuNZg>8P zZ1AGHwN+eDAQ%3E0_VHsMYz* zT$MS_$y1&nmB9}RmcyQ>AjD*Ph)VCsgtq^S0EFFf(ZNIDDIfkzx(E`sY8GZ~zcb@E zo5khykal2)lGeBaM9l|GHXFajfZaKf3CbOri$%{z``ph%r>o?n&=~6yfrS5OfirF% z-wk14;YWJp2$juC^5F7VMFQ`8OI{TivP=5&ofJ8bt$Fq*3R+q+2mwvvFZ?K|sB;C5 zoI6Ig#nXmI6I=QN{{3lMOE`{#zlj3>hp?I)E}CDb(-QI*`Uyz(GWn~TLj|XFl3+{75vB5fr*Y+?)e!B0P1G9rvrJP70XTZ`2-u@v$?30g?dXvhYF{)9C=G>PT0qFLH z3QQwOqQKLyV;b@77eyA$JYUf=ITF}5!)$mg!5|2+7a+q>7?>(M43)!_ORxDbg4~#t z%j_)v84?{@H4b+mhPdFeYQJ;_%}{T%c*UF;&O>ZHM+zQTVsmp4-)~s3RlPNAU&@}5 zRXlq(Wng%`O&z0|OE?Gk=74-4K0iNWMFf$EYxn!@G>PQJh>^66OjdUd67({eEoi9R zb61)Gh80mJaRl=Bew8GmdZc6q78MQ~FbNn?pd0R$2n=*I(2Wo-ZMb$W? z+16~~Liehrq@SqOjiNm}+Xa{D2?pAF^KGJqmGY5P;~O|HFRt6WC+eH5ijl-%wKJVX zb$pN7JdjJY>Y5q}X=xw>0zt}1{a(2UEvyd`60)J80X9aF#I`pc11`bqWiV5BLWG1@ zH3{!@QBW0qmTj8?`cOioKzVPEG%NGiscE`*zAsMsz)XnjS!hS0UY4%${cTl}^|EB{ zxTSQs^m>k)$6Hyo_m)!z9;(IZx%Vl6N+45Cd3Z(+E?|8roe#FNT^Ek11X@;x{^S{`>@Ox6ZxV|6q!Rswl13ZD<4J`WTQf4I*c zNP>yRaj~%mhK3$@$9LwF+W5ugTn~4mbeXeN5hZw`#J#2VI>kEoUWM$U{0V$YibF2>l%imOrp90WmQog#>j-YR;Iq49Nv3ycq>P{wZ#peh=RdHg%C=21W zqik_}p#x?PZ!=Q>v#BM=IP_*6z!;O$NALOmPn-K!%#56DwIGH3RmhFoGm5KC{`p;t z$c|6TZK4l&9ofHieS_)~0Ar~fTwDV{#u@liz{>()_4fTK9@ook%|>hc=C(vh{i+iR zMvEQv1z;yi)tTeh*+JwLRy;Qe2aUp09AOt{OUQ^(>U@g69Z5od)jh!%b(M4C}~{OvTcj^}*NXWa0T?-o%V@9*fMZ*^$*>Y%W2!twwB0LZZN^72DNLttRQvqy=N zxuN0C{(e6_jIcZln%o*~A!`=?+N6k!s9hQ#i}P8~P%ujRVB5_k3ZN4WOQdkD4(MIf)%q zXy1Gmk?6@psVvv$EK)yw(;Y6FOPe~Bi#qZaz+fAy0OZU__0VcO-U|(zM_jeD5J~mN zEP$gn9dP!@)Q&;ruJg546Dz~9>bY>gt*tGff0X-%GP&jVfQvH#_W6@|>=%B5K#ZUq zGmQ!rHcKhkQvXt?!tCtL=>ka|9i6#F=Ewq)qAu0^&-h=cM}WWl1PL$&-_nbdNeHCB zTSZ_;K;Yy*Xve=9$N$id|MG_ax0n1&PX6N({^1Q>HuS)CV?~frP*6}&l{GbC5R#yU zjg5_IHds<1KzzrMLnX2RF-6JG&(~^motmDWURhb0_^W^u-QC;UePL#1W;S;U$>lpY zCg(D_Wn3zr9(%h9G4(H3OWT7^S=6l+mgc4N!avC-?q5e+|{G$;A@+GXw_cX^*ns@KnMdDyPM+p&LG>b=`{l$`zzLh zo}}@Y`U1c3eR`(?ZV`}Afg;lm=YUp_99tPMa^7`(M$6+5Pa%U`!ZQ;rqNSEP9 zITNM*>@p)g^Ua5TrLeh_g!OjET<+VC{Lb#izw^4hPjON>@HK4KMl}vE?UHiwZMd;{ zhjX{nX2pHh<6v$Xb_mf3rCyjFPx>+~zOoRPQu!(Y#C~o~xPJ1X5%Qr7xng z^PSw_A2`McguuVD-P|4?9?Iv5Fu*7pd_(zAC9ba2E5tVKbuz2jPm2ayEZt;{Wu1qBB( zP1neIuBVwfbj$i4vw!DEyD~uDp^=c0wY9YBG-#w}mQ}OOQuQ%ROb&qDIeCm*A^~B{ zx+Y2up)!j%Bavp*oL0DMWi6Ud19TTVYR_)orb+J18icFRD z>zdpzpeeQ^Hl0Is+Ng4Qb7noAeBh0R-th7vEE=UrHbM7()?~h3nY=X2u?WgVE@RW4 z@aPjioQ*3>3PL8H$Kl3x)?1T1KOEk~hC(B>>QA{lsY;Vx_I$K_JV(VF&ii`a@upYz zv(zswfQgX__yBFRENLxm>YXZ3ca{Ro8S}F~TuAdbmXq7S!*aP;E=+fTeN{dCsqlxw z%;rOErW)y-&+Jn&hedsOOnC>@RhkjHEhk~3idqGCW)sd*3uepZvYBoMm>g}*4Zlc6 zdDt=aUyXvZ>H;QdR5^s>CCW$J>p%ya5dC6<5AGtk_ zYM@hh#P}$lspuNqlVPq$MIshx%OJ!0>ySDufB;%RXj?6D*I%l#BWxg;qav;hYjBhv zoI(~5saLYB+66Z{rkwS%BF#jCTKABHDRo6b9G>3B2E^cIJ8Y9Eq z@LCh2@kQUVIReE-^c6*yI!`yac_3w_6Z!ywy$ZDb!^nP-URJuRl53!g#xpDJ4)frXG)%}#m-6HCqjz9;9Cp0Tix1$(61-a0Y|9CBYCKMqV~P6C!mR+FxLv zrDOf}(wtEs93yM3A>8SliROsWH4+%Zi_azi0f z)T`?ZN7n=#@AVgEZa6qNpVzBkDYDvMzvRm1C=*JJtRwZ4fx;N-$I;Odu-(hd%!HY- zwF~^uc@?jKVmj6!SAmZxkkPG3IBnsMp?J0Z|BKALV1^I~iEf3P{MgtFjzN#b1+Smm z0^av1)!9=NXH+Cu8D9~7liGZbqy-yMoP2Qb6E8?xY;GYywjJ~X5@(>fr3Kh*@Or-{ z8><6Bw)v0BjEIO(Pn4FB_!$v#HdnS##_!^lU30#=fZy(_(8*fpP7;YwHtd$;zVwi? zjRU6qE|=l?66&oPHe3z$|F}{qFc^(GBfQlyTHQdyIkz9o3tyCsp$#KXy?5zrH0R1G z|2xnoVf-`D5{_bR^{?^9t}Xh|H;)ZOZe!`1ZZa-?h37-lO{FBN2>N;}yU}90^0a7) zTA_SEwzk-5ttgcg3OWiASmzdX&g01+&VNS9$#;d&5vlI9YDT-{2QUadi-FxXy@)@!J3iAmY4bBg-RYME9$9HbZ zJGSK{ncpN|<$HBN1fNhsY|VAoic02jUzvjTnl6%G?S(%<=P%+IuLtp$*W}@JeL#c9 zJY5IHVjM5{#>B*gkDmoh{C0PD{rx`&Mk`U)S6ACPI2d9C<(lh2s1E#)!bDMcYW^Du zo7A#7{$EAmB&C@L;eTU8=ZyN=Js!%f$~hWR8R)sWJ-Y)Tp?-YkbPADGO$xw$C=Zx2n3P5(S(uo>WMtPXUc3MJp6kC&%E<>uj`sip?RV+IZ<5;*G`-+dZOWiVzafAOfVr=a8$w}A_ z`+%KB1sY+XesV%WLRHm83X_Q~j?H>obEJ!^)m*{C?No;YyrVYEm?}~6vt~Qwda&D20sLW^yi}|9>SN20p6mR z-u^k0{_^S!o%>H#|5;WqtCwI`b2B>WQD!B3wZ|(~=COvRo7sSn%YY*u5!v-Sz zOFy#S(IQ@1nP1foQ*#b`kEIuGbVA9G{>zZoE@AA=LvfPkWN1aOXB>B>zRu?NZ{^lp zC28H==M)wq&Bsc0HW;o}^W371*S!^=PL!-FCIkJF*WHy)%f-Y=Gef&Sb`Tv+z6-d>rVnl)eEbNzvBmf>T zF3F58mL?873VOTjM!#2Ot_CW3%5YljgdZM$pt;kfu@ooxeb+PPGo8=Hi}LAA9GRvt zk=cWNG$;+Oh$ksvtwctPFeCL`C`BuiU{ggYQ?e;HXVD>HMKMoMnj=UYcS|;7G!;{Y z_KGEsb;02^88YQc2k?D~If(-{QwuIQoF*%qLzvYcI<0PJji|vs=4@tj2R&!Kiz5JB z1zrUWmk(FKW>H1~f&l0R#J|tiiH9A$0fpScpT-Dm1cp$P|azX z3=LWsG7^%dl@+!@s>Egp1p^M{%Y6(_XJ&+$rw-b&(`il_^fC5TJeVVC-an-E1}ED? zr8mq($X>a2CCf!gnjhZhq}Y$M=1$tm#>!9TnRuP0R0i(2MPI?zIK8%Cf1?u0exrJT ztbOCby}c@=wQnCyRqoYsGdf*fEBAaL?q|DrNwHZ>Qq5AxSm_Z>^z9E02*7%)9UV z&As#Pd;1^yt3F*+S67`{d+oK?p`A9Xlgy)rhhaiM4;BVxG4k>80hQ{hsTf^cD^v;0 z7JJ)It>8;c;+3Nr@CQLn#Y)X5zc5M_+BdabJ#k?)|p_QL=)_PLm736e6DaRTyg_<_GW5QIgBy^{I0%S1T1t$ zh$KViJ8FUT3{u^N*|gz)AcJe0d=JNQ*merLpCr^_0pVpVixTnkk=cFHpBufXEM4gX zHEk4T%y#jc|2q089}7IH02B=r{D5X%LBW?Gaq76m`T54CCME(r6(*ggLkz#Ab%ypas8;5-9=*t*dQu?+{m*LZ&(Jr-Mh8q!4VT^j3Em`% zm@LY*sb!6bk{J^f^%UZ9dzwY;x7E9=ebY2Xkkxjx=U>z2j}xHo-9N(!$TKaDEKG~z zJ-+~#0g!8G(gz|E);iz>*mC0I_a#Y_g9;xPnZre=8tu)*F%>Ks{Xw?tUC`d%&+2Bl z`rZyo5@YM?)y^0!mcr{C0V=I=)F!QYli zvA3R`z-8*VH^e=gXTWT+ zSZCh1Zu1^r9Mfp_1?yXdqRYp-i`m)PmoHy-{t4iPii!%*%{?|UVmVm=+960|u~fy9 zU+PnuOOW{-e{0m?p%T}4U(-7mS4KAzAUr`WWOX~N?s)MK+!uJLeLN}@G&}GFF8o~#t)Li-Qk08>R?j5gPD%l% z9V)2y{%P!OypH{&-TJj*1UbT8x1T-_>CTpCo28NSOX+RFDZ+w++}tpHuJ2?6=b)mn z&MyeKtd#Whqtny1$E42X_VdRh-6Kg+J3JC`)3ICRIzi#uj2uTxjx~J3I3PHt@U)dM z;yqC{m@Fyl-dv}9vuhjdxBPg!8dta%BL#;;-iBZRulMs+U8VM3IuM*P&}Q_DWajl%22VeOm%k)Rm`D7WmWjRhx<;pva$lCf5as>vD7g%)nGO~DvWpP=wWsm)jm+c;7U_v<{gggtyy!=CJ&6ow%5849`1$U+Y-kw)1*9Y~*;zwjOr+wo{IW5x_jcc1}JR~j1g{v33<2(eyDSo+5g{Kw*3pKH81 zM6{z7;fN)@KG@w6%XEnFcnhFAfANf(Xd;@;pz&ZbCd){F*thnT>xc{%K&zR=CeWx_ zx3dkuBa628=pjvqlIo)mZ6+x|nH1n^Ga4}*xRrq&>p6KtR2a76T(VD* zGouhbk8veT?oJXTVzIh>s>DQU9Lav?Y%p_EqBOCFM^dpMJCBQg(-)og_JQh}VJ)fD z3PQ}GuBNKfJ;>cole5doppQT-yw8e}pt$>nXlQ<*E(bo<3`!>VvG5TS?pvm5^D*pr zu815yuS23-Z^lG4Rq{C@v2c4$`=LJF4_n;_pDcY#W_teV_kR78dS{g<`N&6lqkUYU zK%Y&aG`k^zZ@>jS=eSYIWQFCCs=vYOa7>$UNt#ehhcao{;2lAQ_?g$!#+^7&|B%z= zzI7EDNryTcZhs%Wmw!zf*M#ARtxuY9f9u3i(+Q7q-2GiICUsr&YSHYZ2(Ny*c2Nm` z@P{`i1H&-LN4kbVH3&T`0b`mddtXtf15xZYX?>LzE(WZRgBoW&N0AAd5DH<&OL1^< z&Fa+g`@qyl2;H^nWzo^{E0OYj@SH8vk7KfegS60gIm^A4S#g{%z4(??QX|CK z{r!~<4c1}ZO5_3k=Uo%qIs&y14J`0U&>icDz*ylXhe6Ouzz4aUo6r$z6lf) zm|g&GNz{W~gP^+WD7==^D`;=AC!3k8r5S#Pib_#hMOeXg%cNt{oWY^l=3$|w^5#Hj zo*$9yKKYwlTMp-264BxYhK6|)CIHmEGl=T^f`fx&)3n?dNhFo0ARr*{-JlGL{CvHt z&$L)6$;k>B02Kmc0|!S(TK1C=b_Z7uYdn}yB7w{tE}}k^>}mh8X@&+*1!c-P# z=dt<}3X+3F!2{My&!HbBtR(p-4uq_Fs%QDbbXwGQT0A7f9Z;=Ucn>%G1V)$a*x7Vs z_Si(!RIkfdZ3-SZiQv(RJTO&5DthI=acKh z1w~q{j`gC-IfC*K3z-Zpe&>RZLMD=SXpxp`&U>hW-~nu%oWq^#5vJg31rUX|4Keq5 z_Pp~~#~GGm1i>5I3=B&x`_p2jEK{$LqtS`hDMSwr0WYyM-ZTkj|AIiOCA%9Lfug>4cxoOskjRMN_f&)pEMh7I@i`Z z;*)>kOj=OUlK3LO5|IaHzA_adj3_gy6*dqQfCc{n2>*b}{~m4rbHsm*HcxqQI$;G% zW{eCCx3{;8l&JksBKv@XiOF0!L14F!&3olUwK+*g&jmlj-~-WSycZP|agt*h0@jw6 z1Slvd_N|05QQ zxn!K<)0|e|^NC8tH_$RWL7Qkq2FkcdzlU$&FV2W0s_HL7zF+gBQ&MQ+B*nsU{dI9< zrrg>HiF>{<0vViWIIiRUr71!;Egc>B)`GFT0Bj zHp}y!NFE64+0lc^{oy+N&&U#|wO4D7th@W6HRVKW?PgC?BB;7rw_*4Ea8vUOBRJn+ zWgJt}zkg@8+YinewC2q6s8#A`fi;TGgPd5YXVp>yi!Mnij>akmQ*JFH} z9gayUFF`@Gyxc83ZYK-VuU@@daD|ac;~^?2QX4AngKd zpWX+lE{nZKA)}yhK3={XAxs|T;bwRxgE-MEOw>$Er=Qex8%Xy!*&Q3K%~N^h5AS|` z%w@+SH&k=d+VsLq?s+<*KmQ5dMMIS>!YYt0V*4>H5J6|Qj(-#M>w6Ku)Ov&#^qDMh(@rnU9EW0l|S;&zsjenRN z5qGQ%<2FDH-e2q;>?xY|V(Mq;egSXKtfC0Pp>p-9(uNsFd~SMHT5g|dcQ~vrq}hIu zNIRU4uwRZgM!X|q?diJ1VwkfK6{r}{w$B{1hbn?u&VO2 zvbiWy$At_S9OwiO7{tfLv29HRQ}pHN#lFUVLL+h}vnyTbNFf;#dn|!vzq?$P^TzYI z_mqB&PK;~cn-4)u2sKBzZ>}eY#7vpbYQ~2FKw0{+{M2V~-m@Xui&>p+CP+qJ&Y+rt zS*>Sh1W^u?#qQc9##>CqvqKUS(nfrqeB@WgWb2K;&{UbB_k5lNci_bNB&wAOv@3883*^g^=cHZ1s+LUE&~I zN|gaZ=yh5!x|!h3x9rpRo{+)-u1%#Omx&Fa6qEuZP*Tnx)jR;j0F6ihq5^wqC;tERsfuzDz-~h|hwTDtcdRL3z(zPcErg z%EriIz+R#B;O6eho9TTA?SUJfpH-xAfQA@4R=yg7;MG7C9X%&Yz|$hYd!IF$@7*8v zNq|DAv@Y;b#ZYEI@wv_VU_na3_KMWka^hr2-gZsfBiA1M12b4_$5MSo_45%4KXb*X zm{P%UB2m&Y*9YF_1mDC+{p78ncO4%)zyAEUA!dxYHESi6WfI{oQ;7xpFmU+P0+D$% zU1Bx0o z41T+U4@i^)>dy_fO0y%e;j*Zao1^7JC=Z_m-$U7{b z8D4#8qPi0Pp`S=tC9-s3-x$u2WT z(vG8c$dx_gyt|!646M;{9Ket=Fuy-MZ{mT*1u1@yaj_U`7K(&Zmzxa|(eV)2UuAh! z49l9SvRG@n2|RU@lam1j1Q5}G0;nU#$2;8|ucY(2hxBf6@M2y!(`~c8Zuv_nIkgMi z-1xBGMBGl@J|&THekxCUi`L-lwYl0uC8{#bWE)z$>kvOHmIBw=MjPyZ4H~WM5WX>P zMz$|fa(e!nBkG9gr^`c8G}*mAOH{6bRj&c=lm?=A?TIy{W>51U?A~BIpTj5PnE8_4 zV@B?>87mwV*P$czo4$U_u@*I6A&eT$>`w?^k}FyA-CG@cPR$o))ZURhSQrfhBNj-= z($dO4QKEoe`TPKighNB2WD;qzH-mpmo&SL>=YRN&INf^KWl+FkMaWW(+tTvB+GTi0 zQdIR(y>HgJ)Qfl9MTolV~&48$h*bH%eR^YTs>9sG+EJtyOo&w z&Q`(6)ueL1jPmX$6K{>(-!dW8Jw=u10>$Qq#f3>Fx-{JXAyRA=p}u|p2_p~SAnEit*n>lrL@x!hZQ?&Y1lcS)QK*xV%+OBdkXL=-1cyJo<&p6V{Tpb_wRS4jL+P0;m((}&dL_S?Z(2#$jB4R{ z7hpvrVGW;0Bot`UZ1A>ySLbf*h?0L=`M%=y4GMKXYZZL1U>D+5++LGk2TSxY*9}+N*eO5x~ zjS97;C#0rg>PA<3I6Yv0v;ftD{q^;%IWQnsoco9ZCGq|E_!vN^Q8Vt6aRZnOSGY_Z z)U9G0krQ)U7(GjrhFaG653802bGeJ>&qYL<19kgL9T{W~gQO!DDTLY#)n}FKN@^gI ziwG}>%ppYMAwG=gfX7r7%ZJi%F*v9wTPP>nM-`KDBMJdcROOTYdchX$*(#C z<|KgKDN9qBpnc`@Yk#W1`f(gcA}TuglB4ZRW@^7?b$dLvKf2vqk(}SbnvUcMG>kqE zdnb;K>ymb<5VdOM`CS4yG+z3gfP0w2W-%n^M#`LEunx(~4@E7t(ptji2V+K74n;X{ zswN0Pp%oNlVfQ31)7YKx99HbC%EN_2i30@31WodUN^x<9#bo<)n7S{80`CwAn087E z6_L}$CYpt;imQJjq`99m$D|(stuiT|+dfSRIZZVMl#mYmSHyk}a#noI$NN7@n#M_Z z>NfG6x01X2>g6l~?IJ2ZI9W5`3FeC{mIp zSA3QP#A<*$197A*FBc(Z4u0cl!fhjIwEoD`3WlqQEU_QuUxU|E5sfIhG00^@XTe%u z4^gn%erQD5yiHT1XbegnvRAIRo!dzA(D$^=2ijK|MO4Tasrtz(9qKr^6=k0K74y`l3f1qlGStq9Tu5j2k<_2Fp#`M zB@qeoF!o&NQ~$czb^ThXZ_z;0qfihoI!=PToO%o#esdHf4ds#-42E>TQC zP%Nhx+~v+((<$Ws`P~NXYuko(7HlZ)FHl#+e#@+e;qxlT^^7ep z9l_9GjkOk(H_?`u!W3TG%lq@v$jg389-2;q6<*GT@sQwk<9E<~XluBX76I@b;l`-=H@m-5gQ>Q1|SwtJT-%4Z5E# z{^go5bYnV;?)-F{#1`Rlbf38Mcq6>|9wN8PEb)!h&t^z_G!OQe3MTo9qUN;HbHwn% z&C%BOx=7*)mS!!;{dQvfW9BN5!2`ufZpVXMC2FeT`z+c3U0y;4Qqu0#)pjN$erW{0 z4pGSjZ^-!Z+9;U;R%_ycBUo#W+{C0yff}xv-#23t!yIuKA!&qWrhQeL2zgJ(>t%*$ zj;Tp;Y_o9pMomcriSL@Fq`_95V&CX7a->&b%{~z`>GaqDiaC%z=2WxqwNqYK9K2Tj zb=bup{oQjnV%c`&eb}z& zx#DDi!ONrxt65$1<9zC0QKK>92h#)>q*HtaequLvC>OTUG5AcI3EVuA8u@*$(xRR) z0)I(|RxBblGNrc}kK>QM7p5k9sxjZMhMTDW0BO2WckY*IK=_72Z+n#4=6Iy%b0l`n z5TT5)=w)!XH912z-4wF`cG9#MBD@w+Rm8NJfHmPv&Ibepii(Ovye>e!vZ$yCAVfoZ z0csRO1dzD_DqldxHkazqfvB}QvJ~KR(TBWeGTO)FN9nlEay4X`p@cc;i1|EYpyO>a zKMfpcQ*+qu`glC(mhHz~y zmOmiNuA#YcD{EeLGTI$?w|S6{l?QH{k0CQdt@L>+)H;rImMHi~Oj8k35Un+@+pzmY zwcmP8wi!dQq87@P)tXNITv_2`V`Brp6%eF<0x-`3ly^WY4xjrqMrg0K3-zI6UFmZ1@ z^N6tJ{3>YbcRA)AWlP>VQ`L%jwRWamRs9PzXw4(3J8GN7ufs-MTv(Y8gwOS%1rH>d zpH4n$wwHxMSziH{mSGh4V*FZr!n?cSnw(#TPl<&kfuFtG3OqemccK3p!m39Nx&zfFu{s%>SPb5-U%vs|y4uajA*9A_5cVYh01{8OyO_f)fk z#FIdget>_?(dpe5zZ?=Rewsq&=4ThEQ5|OCuF~CKVudS(r%i+5Dcz#j2Tk#Oj}(FT z7*7*jioFPyn)lG<5%?P>N<&zd<6IWK^JyB{`G@^e@1>_#-7mWqRzV0tWdd6V;mNVF z2Ij_6igkyt0sC4he=eYp zn{{gBzWNjjm^uX_6SZGkVOlRsPdVImm_KRVrDJ-tXcsmL-F1{ev}^;-oXg_?3#O!` zcOECe{%*hWx?L6;kEPRrxq#NYk7^Bil?VW?{>Kshdi~OT_P<5KFHNv=7548gcFW4j zUcY+v&G&ZzFM!AUXof&WN{R-!;1kA`Z2FrdXNS>REj3|FB1J77c3riN6v(-n^2Wg! zmX0ckU$M5wB(GxG^N`s`3>kDgsU$VC6chLwls)-!QI;@1+`)*TY)9xZT5aKwH=rEQ7@J-lU&EQ%&`VDHW; zffKq;RFL>T3;#50U$=|;oKAS`_Ky`2^-{RJSZO&g6*&|+IZappo%;Tj?nUcuab(o4 zJ^tJW+Y-Lpk;Az55(4SXynE1$Qqn7)IWM2hpGZ!H^R-+N`bHtN^Nen5M(=tur!F%% z?n0RSOcWGTJ;C!4bZZvtM~O>Xr^jIRl)EA4j>gB^?iccq4y?1=`D$x#j?)ZC_u=s@ zZ#LtFLRKE znRXPswl7wT4PYbpAV4Lnhs)FQuKU!o)DQ(G#(Z-0VhB2>%$h)sDko*TBaKC9t^MX0xTyNbdP8Pq1uk~@?)M;l~h9!jJx5=@A{daaY-YF=>b zVAb9CM_RCjNyG2jXufOt0dcdiX>fS>^7M2Zd<7-AXZ{}U8<_-9LIRvKZaAeZZ4Fm` zDVcX~g&ewtC*onQlAiVLncKaA0ooT!%`a23%3kZpXXZwsq67HS5a=dLL3)az5+ezG zBChEUXyEvQGO5$PXvEtsV7+#%FX5^#^bjf3p3K)n3+|7^L)ICQx1;6zIsEKqU@TPX z0pottGfLN?Bh4^Tv*hrO*=cbr(y~eXX^unZ(FU3LQZ>`s&*rrGbq$ZLIYeEVol|6z zOD$o{qx5WW?DN(;?ifXt-M4+WPHBF5au{T2DvL3wT)P!jfdS6!#jVbpwTN)liDzQX zizDG;{~LYHIA+BUWDz+zq=LLU?X5|PI8{_{h%b+pxva|Rw>jQGeFN0>z_JA$YG=`| zV!I-lMa0dCdqN3$hO{i$&z1fT^?^%W+romDWW%R zIJ||#61g08^E8hmR16+6N_uxp+j)(F$z@2`WGlZ4V1xYyKdPh{VYd)3@302XeBzp(S z2#TSYd-&`C;l7?8AO(I4owGV^E7{(Kye?Ul8RQ3^ZTh({Lum%0nifr4GH z`=wt~C;A(aJ*Af-eJU1>nwt9jYICQveg{3yjT0}M2{CKhWdh2woN(rKcw>A+HV$VgS!UNbfbwTt}i|%3gH4ckk#L($S zV;rtDDhs_weHv-C!YiIaDwOxB%&w%7YE~f&DaMrZn);qiKZGpjAY~C<+oKh_bgkhj zBs7xvU|*45T*V)#YfzWtCE?XfW#8*3N5|465%5VZzF(^iVpxV^6tcoZKt!xlr;FI! z?q%|n+)KW~Ljmb#Wo;V+t>u3s{AZlI8P?c}BGALgK(sZZ1j551-L!utD9MKWt^llt ziW%c@-PCwHv5WC6f4jL~FZ(C||4u=#tJ92smt3YUezlBrX0EJh&WUEJxx;;7avQbR z>$RKn$;NvuAgL08Bfj(kSqU0K&dpGSQS;^Ora_ zSmci6wO3dvy6}?|<)wVCR5r_@8 zuDW#!fG4@D=UHyYxH)^TSqgnjXpEUwxGD&&L^k9HJ+i8~Fh38>g$@VP5=BZ17&CKA z;LVqiAqKW76IPsnGndw|Fa)5#rFp3NNm1yxPK7CZsKd+T#@ZN-`K`9}Rr6K3IXWw= zE)^z}R>r!_-=ryy2(#ogV6&oGi-Tqb&nus@zvW`q(*LTQaLDJs{B5xL{054n+U6Y> z#i7%Dl}27V(c5>@<>H6T)>8-VU1s_LQL{G-IB*Na-68q1 zziYsbOC3^~ROxCU=*6$8$6tVuWQ)bc#Kki6Xi*_yFlS+=P*G46#8AkE2$KMWeYj|j z67>*;FF^nO`0;gU8)&HeObtkt?xGDg(}WfNs$Ma@Aiv1WH>%Hkz|vau$Qxh&QL1AX znB$Ap%dGwl6-!$}l*U%_)x}vSTg|#TrWv5!tUuJ%abQ!PIL&iet`=MB>R=G?bluLs zo)AcIAZSU7J5j<3BB8>axiM!7(+uEV7O z?cf!k`km)}hS0ibb>sb`Zh;m7)Gbtou~SM*@lp>;itk6Wv~JS)kJKP~)RO6Thr)vw zG?qz^^^gv@*sc66^b?vbEX`RsCR_5Ni77bZfXs(RxsdvDE*ItE@o4Ve&8pbB7CZ#7oCr5a+O zXu)L$h`PU5K7h$I&M}4Ea(QJ1I6Hu02@ovIzXNa*0OEMHZK=jsuIjU<{Sjt2Zo6rv zaDDz5eMXC7CNb*=uHe4&*QXa7 z<=2J})|gOg8kHzk0?dFUQEd9LN@@#({&)+Wm1!DA%-Y5yxB*eK{nc6%o5wOYS1&vG zasZpA<0%*M;;!{!vx<+tl;GLaZ>om?EIR#EXU5ByahD=&>wZ(7elC=SL|i^!)ko1O z;IVD_kS{P80>7LuMjN))X1yKT??I=R!g+a?*7jjsOY>>VMEP8<tDBB`#=)W?zN=oKvZNA&&b6{( z#UEWG9AuX?^1`{&Sz;i3;-0^*v_u8Wv9&IRzsV?BZsf9X$VxX~==QcNlv^hXukch#w}ZyJ_B_18bM!Raw;JYGw;o`WVq^rv^>ycUyx@Nb!+$5d z|4QZaOGqK(hRQ=(O&=#;q3AuZ7_du$_;-(^rRa`>Zh&G3i~@1PcVxWykb!y;N1`Gi zNLDGqeB=L#(xaD8=W26DR#q11paa$h!wMFTq5>R_o6j4(sQ{~D&xhX?LcGtjXu&-r zBS%k=2f%3g_lVZFI05ibuK;gpd;1HRct=+qDKa#1!1s97zCh@|P%wQ}f%1YSeIXN` zZ<;16hSCFjUek#au+BLOh})ywU|ty_eylMu1NuTgQKs{Is;j766So==Mj8X&BZh_| z-^rlP7e4}7y9t&9cN!?Ge{}SCv96@4i7RHnVx=O1Od?4-J~^2h1uiT+9KZum=LdgA z(;L#o3^Y6J>seXJe&50yDN`?Gw_F6w@bU@@ye}uj>f+g;{`_l2uW4&5tMWOpK&tA9 zUX>EHa@onNH$K3LANOEN8b&Top$u`m8W4hm8pQo-#NAOo#sKT{@wedrq$B-3)bGtN z62(F9f3pXF|ND`HO{y5YJ|zn)%y44$;`hE@90aoQ?M2?&%ShL$+jD5S zqw(dj$pUzc%z_zf?&#c^8|N_%w-MXNY=R*I8JzP#cv~L!;qRX4d?hU}%!`d78%-R6 zA6E@15^A?g>P-2_X&0-8Clck)8HtYz5T}S_*Y3j$;IAJYC*smyevn(PzeKU#SR5nZ z95HT3Hbng44hC~Hdyk&c?b7Cpja{<;L;>}e3av>lb^;)i|`YG3cYkq#bWf`IYbhfIERaFQ(@Q+u>MC1CtYqN7apsbteJp=zF?=xi)Hew1_ zd1T#-KK~<_059Db*ZnMD5uDbGrHsR0uASQTAS6|j6DFgl1agk&k%{<~Rrf~LFB7$$ zNB;N`Rhz%|FMtIAwdu{Wtl4A~)d{A)Dqb|c*kyvpJbP3&ovfF;UpuV|ePTsQnjC9Y zE9dWiWg(tJ}I5>lxwZf~&%2kxcJNRnC4-seZ$H7hUP> zj9#i&ZOZ(mw?6nt-U`$_KD1P=M?F{tCZ=jmD4_DjI^I- zoV>k>KU#2YippK9gF(RgJu83sVM8xeQueSS6#V#%bi{Sp7e4$A`(nSG(2)=0=SMPs zlstJ8F80Z*HP8`ftuk0&31J!2bgu91pbH4nry1~WvFNy)i zdmClPM@di7@{a_To1=ta4+U1tK+O8lHn>QAE0z$Gt-`!-u zQ9=e=1r#tzy9i7jaP(APr!oIJn}yaG%iAe|18F5X8m=MZDXx5jt?y*?2{%34?l{IM zgm<)+-KZ+V^BNu8R^?4geLshMn%tVVK*gU3ZZnU62k&^X=g zX11lkqZ0r&_v=EIw>FnZ^lISmwaV2xhOTs5wZ52)#X7!qe)8ndkw7`<8Xgj;`0VtP z*#N}BU)=5{GsPrSCt56yQZIdMrjS;KtR^k=STPV$+uyA0#}XRF@HbHoxeUL9)cgK?W&|~5Bwn2Ck4bO9(02X3)O(--Or<1lz(A|TX=dL6rQiIuPc=-Y+AkYU zphN9Xr)wKPi_dguBXr+-c+Hh-E!CPTg2DbD50=hPg_vHnCJY+YEZ|%VwywPvkq30* zCBPy&SID`NGTq3%FHYM{>K5;c=3J~I{+F9BQ~Fry)t!K;QO^Bfn$0hAtEbW4*K%#e*tD4NqqnS diff --git a/docs/installing.rst b/docs/installing.rst index 30c80a5..168f869 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -9,42 +9,58 @@ operating systems, including for PCs using the :doc:`remote_gpio` feature. Raspberry Pi ============ -First, update your repositories list:: +First, update your repositories list: - sudo apt update +.. code-block:: console -Then install the package for Python 3:: + pi@raspberrypi:~$ sudo apt update - sudo apt install python3-gpiozero +Then install the package for Python 3: -or Python 2:: +.. code-block:: console - sudo apt install python-gpiozero + pi@raspberrypi:~$ sudo apt install python3-gpiozero + +or Python 2: + +.. code-block:: console + + pi@raspberrypi:~$ sudo apt install python-gpiozero Linux ===== -First, update your distribution's repositories list. For example:: +First, update your distribution's repositories list. For example: - sudo apt update +.. code-block:: console -Then install pip for Python 3:: + $ sudo apt update - sudo apt install python3-pip +Then install pip for Python 3: -or Python 3:: +.. code-block:: console - sudo apt install python-pip + $ sudo apt install python3-pip + +or Python 3: + +.. code-block:: console + + $ sudo apt install python-pip (Alternatively, install pip with `get-pip`_.) -Next, install gpiozero for Python 3:: +Next, install gpiozero for Python 3: - sudo pip3 install gpiozero +.. code-block:: console -or Python 2:: + $ sudo pip3 install gpiozero - sudo pip install gpiozero +or Python 2: + +.. code-block:: console + + $ sudo pip install gpiozero .. note:: @@ -55,24 +71,32 @@ or Python 2:: Mac OS ====== -First, install pip:: +First, install pip: - ??? +.. code-block:: console -Next, install gpiozero with pip:: + $ ??? - pip install gpiozero +Next, install gpiozero with pip: + +.. code-block:: console + + $ pip install gpiozero Windows ======= -First, install pip:: +First, install pip: - ??? +.. code-block:: doscon -Next, install gpiozero with pip:: + C:\Users\user1> ??? - pip install gpiozero +Next, install gpiozero with pip: + +.. code-block:: doscon + + C:\Users\user1> pip install gpiozero .. _Raspbian Jessie: https://www.raspberrypi.org/downloads/raspbian/ diff --git a/docs/notes.rst b/docs/notes.rst index 5889f92..b704a8d 100644 --- a/docs/notes.rst +++ b/docs/notes.rst @@ -102,4 +102,4 @@ the ``pip`` utility. This can be done with the following command in Raspbian: Alternatively, install pip with `get-pip`_. -.. _get_pip: https://pip.pypa.io/en/stable/installing/ +.. _get-pip: https://pip.pypa.io/en/stable/installing/ diff --git a/docs/recipes_advanced.rst b/docs/recipes_advanced.rst index bb99583..39db647 100644 --- a/docs/recipes_advanced.rst +++ b/docs/recipes_advanced.rst @@ -36,7 +36,9 @@ functionality without the need to wire up your own LEDs (also useful because the power and activity LEDs are "known good"). Firstly you need to disable the usual triggers for the built-in LEDs. This can -be done from the terminal with the following commands:: +be done from the terminal with the following commands: + +.. code-block:: console $ echo none | sudo tee /sys/class/leds/led0/trigger $ echo gpio | sudo tee /sys/class/leds/led1/trigger @@ -46,7 +48,9 @@ Now you can control the LEDs with gpiozero like so: .. literalinclude:: examples/led_builtin.py To revert the LEDs to their usual purpose you can either reboot your Pi or -run the following commands:: +run the following commands: + +.. code-block:: console $ echo mmc0 | sudo tee /sys/class/leds/led0/trigger $ echo input | sudo tee /sys/class/leds/led1/trigger diff --git a/docs/remote_gpio.rst b/docs/remote_gpio.rst index ef19b88..dabcee3 100644 --- a/docs/remote_gpio.rst +++ b/docs/remote_gpio.rst @@ -7,7 +7,7 @@ Remote GPIO GPIO Zero supports a number of different pin implementations (low-level pin libraries which deal with the GPIO pins directly). By default, the `RPi.GPIO`_ library is used (assuming it is installed on your system), but you can -optionally specify one to use. For more information, see the :doc:`pins` +optionally specify one to use. For more information, see the :doc:`api_pins` documentation page. One of the pin libraries supported, `pigpio`_, provides the ability to control @@ -23,9 +23,11 @@ Preparing the Raspberry Pi If you're using Raspbian Jessie (desktop - not Jessie Lite) then you have everything you need to use the remote GPIO feature. If you're using Jessie Lite, -or another distribution, you'll need to install pigpio:: +or another distribution, you'll need to install pigpio: - sudo apt install pigpio +.. code-block:: console + + $ sudo apt install pigpio Then you just need to enable **Remote GPIO** in the Raspberry Pi configuration tool: @@ -34,21 +36,25 @@ tool: (Alternatively, use ``sudo raspi-config`` on the command line) -Then launch the pigpio daemon:: +Then launch the pigpio daemon: - sudo pigpiod +.. code-block:: console + + $ sudo pigpiod To only allow connections from a specific IP address, use the ``-n`` flag. For -example:: +example: - sudo pigpiod -n localhost # allow localhost only - sudo pigpiod -n 192.168.1.65 # allow 192.168.1.65 only - sudo pigpiod -n localhost -n 192.168.1.65 # allow localhost and 192.168.1.65 only +.. code-block:: console + + $ sudo pigpiod -n localhost # allow localhost only + $ sudo pigpiod -n 192.168.1.65 # allow 192.168.1.65 only + $ sudo pigpiod -n localhost -n 192.168.1.65 # allow localhost and 192.168.1.65 only You will need to launch the pigpio daemon every time you wish to use this feature. To automate running the daemon at boot time:: - sudo systemctl enable pigpiod + $ sudo systemctl enable pigpiod Preparing the host computer =========================== @@ -61,72 +67,100 @@ Python library on the PC. Raspberry Pi ------------ -First, update your repositories list:: +First, update your repositories list: - sudo apt update +.. code-block:: console -Then install the pigpio library for Python 3:: + $ sudo apt update - sudo apt install python3-pigpio +Then install the pigpio library for Python 3: -or Python 2:: +.. code-block:: console - sudo apt install python-pigpio + $ sudo apt install python3-pigpio -Alternatively, install with pip:: +or Python 2: - sudo pip3 install pigpio +.. code-block:: console -or:: + $ sudo apt install python-pigpio - sudo pip install pigpio +Alternatively, install with pip: + +.. code-block:: console + + $ sudo pip3 install pigpio + +or: + +.. code-block:: console + + $ sudo pip install pigpio Linux ----- -First, update your distribution's repositories list. For example:: +First, update your distribution's repositories list. For example: - sudo apt update +.. code-block:: console -Then install pip for Python 3:: + $ sudo apt update - sudo apt install python3-pip +Then install pip for Python 3: -or Python 2:: +.. code-block:: console - sudo apt install python-pip + $ sudo apt install python3-pip + +or Python 2: + +.. code-block:: console + + $ sudo apt install python-pip (Alternatively, install pip with `get-pip`_.) -Next, install pigpio for Python 3:: +Next, install pigpio for Python 3: - sudo pip3 install pigpio +.. code-block:: console -or Python 2:: + $ sudo pip3 install pigpio - sudo pip install pigpio +or Python 2: + +.. code-block:: console + + $ sudo pip install pigpio Mac OS ------ -First, install pip:: +First, install pip: - ??? +.. code-block:: console -Next, install pigpio with pip:: + $ ??? - pip install pigpio +Next, install pigpio with pip: + +.. code-block:: console + + $ pip install pigpio Windows ------- -First install pip:: +First install pip: - ??? +.. code-block:: doscon -Next, install pigpio with pip:: + C:\Users\user1> ??? - pip install pigpio +Next, install pigpio with pip: + +.. code-block:: doscon + + C:\Users\user1> pip install pigpio Environment variables ===================== @@ -135,7 +169,9 @@ The simplest way to use devices with remote pins is to set the ``PIGPIO_ADDR`` environment variable to the IP address of the desired Raspberry Pi. You must run your Python script or launch your development environment with the environment variable set using the command line. For example, one of the -following:: +following: + +.. code-block:: console $ PIGPIO_ADDR=192.168.1.3 python3 hello.py $ PIGPIO_ADDR=192.168.1.3 python3 @@ -147,7 +183,9 @@ pigpio Python library installed, this will work with no further configuration. However, if you are running this from a Raspberry Pi, you will also need to ensure the default pin factory is set to ``PiGPIOPin``. If ``RPi.GPIO`` is installed, this will be selected as the default pin factory, so either uninstall -it, or use another environment variable to set it to ``PiGPIOPin``:: +it, or use another environment variable to set it to ``PiGPIOPin``: + +.. code-block:: console $ GPIOZERO_PIN_FACTORY=pigpio PIGPIO_ADDR=192.168.1.3 python3 hello.py @@ -160,12 +198,16 @@ with no modifications needed. For example: .. literalinclude:: examples/led_1.py -When run with:: +When run with: + +.. code-block:: console $ PIGPIO_ADDR=192.168.1.3 python3 led.py will flash the LED connected to pin 17 of the Raspberry Pi with the IP address -``192.168.1.3``. And:: +``192.168.1.3``. And: + +.. code-block:: console $ PIGPIO_ADDR=192.168.1.4 python3 led.py @@ -236,11 +278,13 @@ computer using remote pins. First, configure the boot partition of the SD card: 1. Edit ``config.txt`` and add ``dtoverlay=dwc2`` on a new line, then save the -file. + file. + 2. Create an empty file called ``ssh`` (no file extension) and save it in the -boot partition. + boot partition. + 3. Edit ``cmdline.txt`` and insert ``modules-load=dwc2,g_ether`` after -``rootwait``. + ``rootwait``. (See `blog.gbaman.info`_ for more information) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 95ff3bd..1651ab6 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -47,6 +47,10 @@ class CompositeOutputDevice(SourceMixin, CompositeDevice): specific order). All keyword arguments *must* be included in the collection. If omitted, an alphabetically sorted order will be selected for keyword arguments. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def on(self): @@ -124,6 +128,10 @@ class ButtonBoard(HoldMixin, CompositeDevice): executed once per hold. This parameter can only be specified as a keyword parameter. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + :param \*\*named_pins: Specify GPIO pins that buttons of the board are attached to, associating each button with a property name. You can designate as @@ -135,6 +143,7 @@ class ButtonBoard(HoldMixin, CompositeDevice): bounce_time = kwargs.pop('bounce_time', None) hold_time = kwargs.pop('hold_time', 1) hold_repeat = kwargs.pop('hold_repeat', False) + pin_factory = kwargs.pop('pin_factory', None) order = kwargs.pop('_order', None) super(ButtonBoard, self).__init__( *( @@ -142,6 +151,7 @@ class ButtonBoard(HoldMixin, CompositeDevice): for pin in args ), _order=order, + pin_factory=pin_factory, **{ name: Button(pin, pull_up, bounce_time, hold_time, hold_repeat) for name, pin in kwargs.items() @@ -209,20 +219,28 @@ class LEDCollection(CompositeOutputDevice): pwm = kwargs.pop('pwm', False) active_high = kwargs.pop('active_high', True) initial_value = kwargs.pop('initial_value', False) + pin_factory = kwargs.pop('pin_factory', None) order = kwargs.pop('_order', None) LEDClass = PWMLED if pwm else LED super(LEDCollection, self).__init__( *( pin_or_collection if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) + LEDClass( + pin_or_collection, active_high, initial_value, + pin_factory=pin_factory + ) for pin_or_collection in args ), _order=order, + pin_factory=pin_factory, **{ name: pin_or_collection if isinstance(pin_or_collection, LEDCollection) else - LEDClass(pin_or_collection, active_high, initial_value) + LEDClass( + pin_or_collection, active_high, initial_value, + pin_factory=pin_factory + ) for name, pin_or_collection in kwargs.items() }) leds = [] @@ -283,6 +301,10 @@ class LEDBoard(LEDCollection): the device will be switched on initially. This parameter can only be specified as a keyword parameter. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + :param \*\*named_pins: Specify GPIO pins that LEDs of the board are attached to, associating each LED with a property name. You can designate as many pins as @@ -486,6 +508,10 @@ class LEDBarGraph(LEDCollection): The initial :attr:`value` of the graph given as a float between -1 and +1. Defaults to ``0.0``. This parameter can only be specified as a keyword parameter. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__(self, *pins, **kwargs): @@ -495,9 +521,12 @@ class LEDBarGraph(LEDCollection): pwm = kwargs.pop('pwm', False) active_high = kwargs.pop('active_high', True) initial_value = kwargs.pop('initial_value', 0.0) + pin_factory = kwargs.pop('pin_factory', None) if kwargs: raise TypeError('unexpected keyword argument: %s' % kwargs.popitem()[0]) - super(LEDBarGraph, self).__init__(*pins, pwm=pwm, active_high=active_high) + super(LEDBarGraph, self).__init__( + *pins, pwm=pwm, active_high=active_high, pin_factory=pin_factory + ) try: self.value = initial_value except: @@ -572,12 +601,17 @@ class LedBorg(RGBLED): each component of the LedBorg. If ``False``, construct regular :class:`LED` instances, which prevents smooth color graduations. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _PiBorg LedBorg: https://www.piborg.org/ledborg """ - def __init__(self, initial_value=(0, 0, 0), pwm=True): + def __init__(self, initial_value=(0, 0, 0), pwm=True, pin_factory=None): super(LedBorg, self).__init__(red=17, green=27, blue=22, - pwm=pwm, initial_value=initial_value) + pwm=pwm, initial_value=initial_value, + pin_factory=pin_factory) class PiLiter(LEDBoard): @@ -604,12 +638,17 @@ class PiLiter(LEDBoard): in when configured for output (warning: this can be on). If ``True``, the device will be switched on initially. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/ """ - def __init__(self, pwm=False, initial_value=False): + def __init__(self, pwm=False, initial_value=False, pin_factory=None): super(PiLiter, self).__init__(4, 17, 27, 18, 22, 23, 24, 25, - pwm=pwm, initial_value=initial_value) + pwm=pwm, initial_value=initial_value, + pin_factory=pin_factory) class PiLiterBarGraph(LEDBarGraph): @@ -634,13 +673,18 @@ class PiLiterBarGraph(LEDBarGraph): The initial :attr:`value` of the graph given as a float between -1 and +1. Defaults to ``0.0``. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/ """ - def __init__(self, pwm=False, initial_value=0.0): + def __init__(self, pwm=False, initial_value=0.0, pin_factory=None): pins = (4, 17, 27, 18, 22, 23, 24, 25) - super(PiLiterBarGraph, self).__init__(*pins, - pwm=pwm, initial_value=initial_value) + super(PiLiterBarGraph, self).__init__( + *pins, pwm=pwm, initial_value=initial_value, pin_factory=pin_factory + ) class TrafficLights(LEDBoard): @@ -680,9 +724,14 @@ class TrafficLights(LEDBoard): The GPIO pin that the yellow LED is attached to. This is merely an alias for the ``amber`` parameter - you can't specify both ``amber`` and ``yellow``. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__(self, red=None, amber=None, green=None, - pwm=False, initial_value=False, yellow=None): + pwm=False, initial_value=False, yellow=None, + pin_factory=None): if amber is not None and yellow is not None: raise OutputDeviceBadValue( 'Only one of amber or yellow can be specified' @@ -700,7 +749,7 @@ class TrafficLights(LEDBoard): ) super(TrafficLights, self).__init__( pwm=pwm, initial_value=initial_value, - _order=devices.keys(), + _order=devices.keys(), pin_factory=pin_factory, **devices) def __getattr__(self, name): @@ -739,11 +788,16 @@ class PiTraffic(TrafficLights): in when configured for output (warning: this can be on). If ``True``, the device will be switched on initially. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Low Voltage Labs PI-TRAFFIC: http://lowvoltagelabs.com/products/pi-traffic/ """ - def __init__(self, pwm=False, initial_value=False): + def __init__(self, pwm=False, initial_value=False, pin_factory=None): super(PiTraffic, self).__init__(9, 10, 11, - pwm=pwm, initial_value=initial_value) + pwm=pwm, initial_value=initial_value, + pin_factory=pin_factory) class PiStop(TrafficLights): @@ -774,6 +828,10 @@ class PiStop(TrafficLights): in when configured for output (warning: this can be on). If ``True``, the device will be switched on initially. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _PiHardware Pi-Stop: https://pihw.wordpress.com/meltwaters-pi-hardware-kits/pi-stop/ .. _location: https://github.com/PiHw/Pi-Stop/blob/master/markdown_source/markdown/Discover-PiStop.md """ @@ -786,13 +844,17 @@ class PiStop(TrafficLights): 'D': (2, 3, 4), } - def __init__(self, location=None, pwm=False, initial_value=False): + def __init__( + self, location=None, pwm=False, initial_value=False, + pin_factory=None): gpios = self.LOCATIONS.get(location, None) if gpios is None: raise ValueError('location must be one of: %s' % ', '.join(sorted(self.LOCATIONS.keys()))) - super(PiStop, self).__init__(*gpios, - pwm=pwm, initial_value=initial_value) + super(PiStop, self).__init__( + *gpios, pwm=pwm, initial_value=initial_value, + pin_factory=pin_factory + ) class StatusZero(LEDBoard): @@ -817,6 +879,10 @@ class StatusZero(LEDBoard): not all strips are given labels, any remaining strips will not be initialised. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _STATUS Zero: https://thepihut.com/statuszero """ default_labels = ('one', 'two', 'three') @@ -827,6 +893,7 @@ class StatusZero(LEDBoard): (22, 27), (9, 10), ) + pin_factory = kwargs.pop('pin_factory', None) if len(labels) == 0: labels = self.default_labels elif len(labels) > len(pins): @@ -834,10 +901,15 @@ class StatusZero(LEDBoard): dup, count = Counter(labels).most_common(1)[0] if count > 1: raise ValueError("Duplicate label %s" % dup) - super(StatusZero, self).__init__(_order=labels, **{ - label: LEDBoard(red=red, green=green, _order=('red', 'green'), **kwargs) - for (green, red), label in zip(pins, labels) - }) + super(StatusZero, self).__init__( + _order=labels, pin_factory=pin_factory, **{ + label: LEDBoard( + red=red, green=green, _order=('red', 'green'), + pin_factory=pin_factory, **kwargs + ) + for (green, red), label in zip(pins, labels) + } + ) class StatusBoard(CompositeOutputDevice): @@ -862,6 +934,10 @@ class StatusBoard(CompositeOutputDevice): will be initialised with names 'one' to 'five'. If some, but not all strips are given labels, any remaining strips will not be initialised. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _STATUS: https://thepihut.com/status """ default_labels = ('one', 'two', 'three', 'four', 'five') @@ -874,6 +950,7 @@ class StatusBoard(CompositeOutputDevice): (5, 11, 26), (13, 6, 18), ) + pin_factory = kwargs.pop('pin_factory', None) if len(labels) == 0: labels = self.default_labels elif len(labels) > len(pins): @@ -881,14 +958,18 @@ class StatusBoard(CompositeOutputDevice): dup, count = Counter(labels).most_common(1)[0] if count > 1: raise ValueError("Duplicate label %s" % dup) - super(StatusBoard, self).__init__(_order=labels, **{ - label: CompositeOutputDevice( - button=Button(button), - lights=LEDBoard( - red=red, green=green, _order=('red', 'green'), **kwargs - ), _order=('button', 'lights')) - for (green, red, button), label in zip(pins, labels) - }) + super(StatusBoard, self).__init__( + _order=labels, pin_factory=pin_factory, **{ + label: CompositeOutputDevice( + button=Button(button), + lights=LEDBoard( + red=red, green=green, _order=('red', 'green'), + pin_factory=pin_factory, **kwargs + ), _order=('button', 'lights'), pin_factory=pin_factory + ) + for (green, red, button), label in zip(pins, labels) + } + ) class SnowPi(LEDBoard): @@ -917,30 +998,39 @@ class SnowPi(LEDBoard): in when configured for output (warning: this can be on). If ``True``, the device will be switched on initially. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Ryanteck SnowPi: https://ryanteck.uk/raspberry-pi/114-snowpi-the-gpio-snowman-for-raspberry-pi-0635648608303.html """ - def __init__(self, pwm=False, initial_value=False): + def __init__(self, pwm=False, initial_value=False, pin_factory=None): super(SnowPi, self).__init__( arms=LEDBoard( left=LEDBoard( top=17, middle=18, bottom=22, pwm=pwm, initial_value=initial_value, - _order=('top', 'middle', 'bottom')), + _order=('top', 'middle', 'bottom'), + pin_factory=pin_factory), right=LEDBoard( top=7, middle=8, bottom=9, pwm=pwm, initial_value=initial_value, - _order=('top', 'middle', 'bottom')), - _order=('left', 'right') + _order=('top', 'middle', 'bottom'), + pin_factory=pin_factory), + _order=('left', 'right'), + pin_factory=pin_factory ), eyes=LEDBoard( left=23, right=24, pwm=pwm, initial_value=initial_value, - _order=('left', 'right') + _order=('left', 'right'), + pin_factory=pin_factory ), nose=25, pwm=pwm, initial_value=initial_value, - _order=('eyes', 'nose', 'arms') - ) + _order=('eyes', 'nose', 'arms'), + pin_factory=pin_factory + ) class TrafficLightsBuzzer(CompositeOutputDevice): @@ -957,12 +1047,18 @@ class TrafficLightsBuzzer(CompositeOutputDevice): :param Button button: An instance of :class:`Button` representing the button on the HAT. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, lights, buzzer, button): + def __init__(self, lights, buzzer, button, pin_factory=None): super(TrafficLightsBuzzer, self).__init__( lights=lights, buzzer=buzzer, button=button, - _order=('lights', 'buzzer', 'button')) + _order=('lights', 'buzzer', 'button'), + pin_factory=pin_factory + ) class FishDish(TrafficLightsBuzzer): @@ -985,14 +1081,19 @@ class FishDish(TrafficLightsBuzzer): LED. If ``False`` (the default), construct regular :class:`LED` instances. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Pi Supply FishDish: https://www.pi-supply.com/product/fish-dish-raspberry-pi-led-buzzer-board/ """ - def __init__(self, pwm=False): + def __init__(self, pwm=False, pin_factory=None): super(FishDish, self).__init__( - TrafficLights(9, 22, 4, pwm=pwm), - Buzzer(8), - Button(7, pull_up=False), + TrafficLights(9, 22, 4, pwm=pwm, pin_factory=pin_factory), + Buzzer(8, pin_factory=pin_factory), + Button(7, pull_up=False, pin_factory=pin_factory), + pin_factory=pin_factory ) @@ -1016,14 +1117,19 @@ class TrafficHat(TrafficLightsBuzzer): LED. If ``False`` (the default), construct regular :class:`LED` instances. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Ryanteck Traffic HAT: https://ryanteck.uk/hats/1-traffichat-0635648607122.html """ - def __init__(self, pwm=False): + def __init__(self, pwm=False, pin_factory=None): super(TrafficHat, self).__init__( - TrafficLights(24, 23, 22, pwm=pwm), - Buzzer(5), - Button(25), + TrafficLights(24, 23, 22, pwm=pwm, pin_factory=pin_factory), + Buzzer(5, pin_factory=pin_factory), + Button(25, pin_factory=pin_factory), + pin_factory=pin_factory ) @@ -1049,13 +1155,19 @@ class Robot(SourceMixin, CompositeDevice): :param tuple right: A tuple of two GPIO pins representing the forward and backward inputs of the right motor's controller. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, left=None, right=None): + def __init__(self, left=None, right=None, pin_factory=None): super(Robot, self).__init__( - left_motor=Motor(*left), - right_motor=Motor(*right), - _order=('left_motor', 'right_motor')) + left_motor=Motor(*left, pin_factory=pin_factory), + right_motor=Motor(*right, pin_factory=pin_factory), + _order=('left_motor', 'right_motor'), + pin_factory=pin_factory + ) @property def value(self): @@ -1148,11 +1260,17 @@ class RyanteckRobot(Robot): robot = RyanteckRobot() robot.forward() + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Ryanteck MCB: https://ryanteck.uk/add-ons/6-ryanteck-rpi-motor-controller-board-0635648607160.html """ - def __init__(self): - super(RyanteckRobot, self).__init__((17, 18), (22, 23)) + def __init__(self, pin_factory=None): + super(RyanteckRobot, self).__init__( + (17, 18), (22, 23), pin_factory=pin_factory + ) class CamJamKitRobot(Robot): @@ -1168,20 +1286,31 @@ class CamJamKitRobot(Robot): robot = CamJamKitRobot() robot.forward() + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _CamJam #3 EduKit: http://camjam.me/?page_id=1035 """ - def __init__(self): - super(CamJamKitRobot, self).__init__((9, 10), (7, 8)) + def __init__(self, pin_factory=None): + super(CamJamKitRobot, self).__init__( + (9, 10), (7, 8), pin_factory=pin_factory + ) class _EnergenieMaster(SharedMixin, CompositeOutputDevice): - def __init__(self): + def __init__(self, pin_factory=None): self._lock = Lock() super(_EnergenieMaster, self).__init__( - *(OutputDevice(pin) for pin in (17, 22, 23, 27)), - mode=OutputDevice(24), enable=OutputDevice(25), - _order=('mode', 'enable')) + *( + OutputDevice(pin, pin_factory=pin_factory) + for pin in (17, 22, 23, 27) + ), + mode=OutputDevice(24, pin_factory=pin_factory), + enable=OutputDevice(25, pin_factory=pin_factory), + _order=('mode', 'enable'), pin_factory=pin_factory + ) def close(self): if self._lock: @@ -1190,7 +1319,7 @@ class _EnergenieMaster(SharedMixin, CompositeOutputDevice): self._lock = None @classmethod - def _shared_key(cls): + def _shared_key(cls, pin_factory): # There's only one Energenie master return None @@ -1231,18 +1360,22 @@ class Energenie(SourceMixin, Device): the socket, which will be set upon construction. This defaults to ``False`` which will switch the socket off. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _Energenie socket: https://energenie4u.co.uk/index.php/catalogue/product/ENER002-2PI """ - def __init__(self, socket=None, initial_value=False): + def __init__(self, socket=None, initial_value=False, pin_factory=None): if socket is None: raise EnergenieSocketMissing('socket number must be provided') if not (1 <= socket <= 4): raise EnergenieBadSocket('socket number must be between 1 and 4') self._value = None - super(Energenie, self).__init__() + super(Energenie, self).__init__(pin_factory=pin_factory) self._socket = socket - self._master = _EnergenieMaster() + self._master = _EnergenieMaster(pin_factory=pin_factory) if initial_value: self.on() else: diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 1a1c687..9cbc9c8 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -197,7 +197,11 @@ class Device(ValuesMixin, GPIOBase): def __init__(self, **kwargs): # Force pin_factory to be keyword-only, even in Python 2 - self.pin_factory = kwargs.pop('pin_factory', Device.pin_factory) + pin_factory = kwargs.pop('pin_factory', None) + if pin_factory is None: + self.pin_factory = Device.pin_factory + else: + self.pin_factory = pin_factory if kwargs: raise TypeError("Device.__init__() got unexpected keyword " "argument '%s'" % kwargs.popitem()[0]) @@ -281,8 +285,7 @@ class CompositeDevice(Device): dev.close() raise self._all = args + tuple(kwargs[v] for v in self._order) - kwargs = {'pin_factory': pin_factory} if pin_factory is not None else {} - super(CompositeDevice, self).__init__(**kwargs) + super(CompositeDevice, self).__init__(pin_factory=pin_factory) def __getattr__(self, name): # if _named doesn't exist yet, pretend it's an empty dict diff --git a/gpiozero/input_devices.py b/gpiozero/input_devices.py index e65b769..4570d75 100644 --- a/gpiozero/input_devices.py +++ b/gpiozero/input_devices.py @@ -32,9 +32,13 @@ class InputDevice(GPIODevice): :param bool pull_up: If ``True``, the pin will be pulled high with an internal resistor. If ``False`` (the default), the pin will be pulled low. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, pin=None, pull_up=False): - super(InputDevice, self).__init__(pin) + def __init__(self, pin=None, pull_up=False, pin_factory=None): + super(InputDevice, self).__init__(pin, pin_factory=pin_factory) try: self.pin.function = 'input' pull = 'up' if pull_up else 'down' @@ -75,9 +79,16 @@ class DigitalInputDevice(EventsMixin, InputDevice): Specifies the length of time (in seconds) that the component will ignore changes in state after an initial change. This defaults to ``None`` which indicates that no bounce compensation will be performed. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, pin=None, pull_up=False, bounce_time=None): - super(DigitalInputDevice, self).__init__(pin, pull_up) + def __init__( + self, pin=None, pull_up=False, bounce_time=None, pin_factory=None): + super(DigitalInputDevice, self).__init__( + pin, pull_up, pin_factory=pin_factory + ) try: self.pin.bounce = bounce_time self.pin.edges = 'both' @@ -127,12 +138,18 @@ class SmoothedInputDevice(EventsMixin, InputDevice): (from the :attr:`is_active` property) will block until the queue has filled. If ``True``, a value will be returned immediately, but be aware that this value is likely to fluctuate excessively. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, pin=None, pull_up=False, threshold=0.5, - queue_len=5, sample_wait=0.0, partial=False): + queue_len=5, sample_wait=0.0, partial=False, pin_factory=None): self._queue = None - super(SmoothedInputDevice, self).__init__(pin, pull_up) + super(SmoothedInputDevice, self).__init__( + pin, pull_up, pin_factory=pin_factory + ) try: self._queue = GPIOQueue(self, queue_len, sample_wait, partial) self.threshold = float(threshold) @@ -263,11 +280,17 @@ class Button(HoldMixin, DigitalInputDevice): as long as the device remains active, every *hold_time* seconds. If ``False`` (the default) the :attr:`when_held` handler will be only be executed once per hold. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, pin=None, pull_up=True, bounce_time=None, - hold_time=1, hold_repeat=False): - super(Button, self).__init__(pin, pull_up, bounce_time) + hold_time=1, hold_repeat=False, pin_factory=None): + super(Button, self).__init__( + pin, pull_up, bounce_time, pin_factory=pin_factory + ) self.hold_time = hold_time self.hold_repeat = hold_repeat @@ -325,14 +348,19 @@ class LineSensor(SmoothedInputDevice): filled with values. Only set this to ``True`` if you require values immediately after object construction. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _CamJam #3 EduKit: http://camjam.me/?page_id=1035 """ def __init__( self, pin=None, queue_len=5, sample_rate=100, threshold=0.5, - partial=False): + partial=False, pin_factory=None): super(LineSensor, self).__init__( pin, pull_up=False, threshold=threshold, - queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial + queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial, + pin_factory=pin_factory ) try: self._queue.start() @@ -394,13 +422,18 @@ class MotionSensor(SmoothedInputDevice): :attr:`~SmoothedInputDevice.is_active` until the internal queue has filled with values. Only set this to ``True`` if you require values immediately after object construction. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, pin=None, queue_len=1, sample_rate=10, threshold=0.5, - partial=False): + partial=False, pin_factory=None): super(MotionSensor, self).__init__( pin, pull_up=False, threshold=threshold, - queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial + queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial, + pin_factory=pin_factory ) try: self._queue.start() @@ -460,14 +493,19 @@ class LightSensor(SmoothedInputDevice): filled with values. Only set this to ``True`` if you require values immediately after object construction. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _CamJam #2 EduKit: http://camjam.me/?page_id=623 """ def __init__( self, pin=None, queue_len=5, charge_time_limit=0.01, - threshold=0.1, partial=False): + threshold=0.1, partial=False, pin_factory=None): super(LightSensor, self).__init__( pin, pull_up=False, threshold=threshold, - queue_len=queue_len, sample_wait=0.0, partial=partial + queue_len=queue_len, sample_wait=0.0, partial=partial, + pin_factory=pin_factory ) try: self._charge_time_limit = charge_time_limit @@ -568,17 +606,22 @@ class DistanceSensor(SmoothedInputDevice): filled with values. Only set this to ``True`` if you require values immediately after object construction. + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). + .. _CamJam #3 EduKit: http://camjam.me/?page_id=1035 """ def __init__( self, echo=None, trigger=None, queue_len=30, max_distance=1, - threshold_distance=0.3, partial=False): + threshold_distance=0.3, partial=False, pin_factory=None): if max_distance <= 0: raise ValueError('invalid maximum distance (must be positive)') self._trigger = None super(DistanceSensor, self).__init__( echo, pull_up=False, threshold=threshold_distance / max_distance, - queue_len=queue_len, sample_wait=0.0, partial=partial + queue_len=queue_len, sample_wait=0.0, partial=partial, + pin_factory=pin_factory ) try: self.speed_of_sound = 343.26 # m/s diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index b570f3b..b715bfb 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -36,9 +36,15 @@ class OutputDevice(SourceMixin, GPIODevice): ``None``, the device will be left in whatever state the pin is found in when configured for output (warning: this can be on). If ``True``, the device will be switched on initially. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, pin=None, active_high=True, initial_value=False): - super(OutputDevice, self).__init__(pin) + def __init__( + self, pin=None, active_high=True, initial_value=False, + pin_factory=None): + super(OutputDevice, self).__init__(pin, pin_factory=pin_factory) self._lock = Lock() self.active_high = active_high if initial_value is None: @@ -126,10 +132,14 @@ class DigitalOutputDevice(OutputDevice): uses an optional background thread to handle toggling the device state without further interaction. """ - def __init__(self, pin=None, active_high=True, initial_value=False): + def __init__( + self, pin=None, active_high=True, initial_value=False, + pin_factory=None): self._blink_thread = None self._controller = None - super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value) + super(DigitalOutputDevice, self).__init__( + pin, active_high, initial_value, pin_factory=pin_factory + ) @property def value(self): @@ -230,6 +240,10 @@ class LED(DigitalOutputDevice): ``None``, the LED will be left in whatever state the pin is found in when configured for output (warning: this can be on). If ``True``, the LED will be switched on initially. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ pass @@ -265,6 +279,10 @@ class Buzzer(DigitalOutputDevice): ``None``, the buzzer will be left in whatever state the pin is found in when configured for output (warning: this can be on). If ``True``, the buzzer will be switched on initially. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ pass @@ -293,13 +311,21 @@ class PWMOutputDevice(OutputDevice): :param int frequency: The frequency (in Hz) of pulses emitted to drive the device. Defaults to 100Hz. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, pin=None, active_high=True, initial_value=0, frequency=100): + def __init__( + self, pin=None, active_high=True, initial_value=0, frequency=100, + pin_factory=None): self._blink_thread = None self._controller = None if not 0 <= initial_value <= 1: raise OutputDeviceBadValue("initial_value must be between 0 and 1") - super(PWMOutputDevice, self).__init__(pin, active_high, initial_value=None) + super(PWMOutputDevice, self).__init__( + pin, active_high, initial_value=None, pin_factory=pin_factory + ) try: # XXX need a way of setting these together self.pin.frequency = frequency @@ -500,6 +526,10 @@ class PWMLED(PWMOutputDevice): :param int frequency: The frequency (in Hz) of pulses emitted to drive the LED. Defaults to 100Hz. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ pass @@ -552,17 +582,24 @@ class RGBLED(SourceMixin, Device): If ``True`` (the default), construct :class:`PWMLED` instances for each component of the RGBLED. If ``False``, construct regular :class:`LED` instances, which prevents smooth color graduations. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, red=None, green=None, blue=None, active_high=True, - initial_value=(0, 0, 0), pwm=True): + initial_value=(0, 0, 0), pwm=True, pin_factory=None): self._leds = () self._blink_thread = None if not all(p is not None for p in [red, green, blue]): raise GPIOPinMissing('red, green, and blue pins must be provided') LEDClass = PWMLED if pwm else LED - super(RGBLED, self).__init__() - self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue)) + super(RGBLED, self).__init__(pin_factory=pin_factory) + self._leds = tuple( + LEDClass(pin, active_high, pin_factory=pin_factory) + for pin in (red, green, blue) + ) self.value = initial_value red = _led_property(0) @@ -803,17 +840,23 @@ class Motor(SourceMixin, CompositeDevice): variable speed control. If ``False``, construct :class:`DigitalOutputDevice` instances, allowing only direction control. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ - def __init__(self, forward=None, backward=None, pwm=True): + def __init__(self, forward=None, backward=None, pwm=True, pin_factory=None): if not all(p is not None for p in [forward, backward]): raise GPIOPinMissing( 'forward and backward pins must be provided' ) PinClass = PWMOutputDevice if pwm else DigitalOutputDevice super(Motor, self).__init__( - forward_device=PinClass(forward), - backward_device=PinClass(backward), - _order=('forward_device', 'backward_device')) + forward_device=PinClass(forward, pin_factory=pin_factory), + backward_device=PinClass(backward, pin_factory=pin_factory), + _order=('forward_device', 'backward_device'), + pin_factory=pin_factory + ) @property def value(self): @@ -946,11 +989,15 @@ class Servo(SourceMixin, CompositeDevice): :param float frame_width: The length of time between servo control pulses measured in seconds. This defaults to 20ms which is a common value for servos. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, pin=None, initial_value=0.0, min_pulse_width=1/1000, max_pulse_width=2/1000, - frame_width=20/1000): + frame_width=20/1000, pin_factory=None): if min_pulse_width >= max_pulse_width: raise ValueError('min_pulse_width must be less than max_pulse_width') if max_pulse_width >= frame_width: @@ -961,7 +1008,11 @@ class Servo(SourceMixin, CompositeDevice): self._min_value = -1 self._value_range = 2 super(Servo, self).__init__( - pwm_device=PWMOutputDevice(pin, frequency=int(1 / frame_width))) + pwm_device=PWMOutputDevice( + pin, frequency=int(1 / frame_width), pin_factory=pin_factory + ), + pin_factory=pin_factory + ) try: self.value = initial_value except: @@ -1146,17 +1197,23 @@ class AngularServo(Servo): :param float frame_width: The length of time between servo control pulses measured in seconds. This defaults to 20ms which is a common value for servos. + + :param Factory pin_factory: + See :doc:`api_pins` for more information (this is an advanced feature + which most users can ignore). """ def __init__( self, pin=None, initial_angle=0.0, min_angle=-90, max_angle=90, min_pulse_width=1/1000, max_pulse_width=2/1000, - frame_width=20/1000): + frame_width=20/1000, pin_factory=None): self._min_angle = min_angle self._angular_range = max_angle - min_angle initial_value = 2 * ((initial_angle - min_angle) / self._angular_range) - 1 super(AngularServo, self).__init__( - pin, initial_value, min_pulse_width, max_pulse_width, frame_width) + pin, initial_value, min_pulse_width, max_pulse_width, frame_width, + pin_factory=pin_factory + ) @property def min_angle(self): diff --git a/gpiozero/spi_devices.py b/gpiozero/spi_devices.py index 621828a..f02be55 100644 --- a/gpiozero/spi_devices.py +++ b/gpiozero/spi_devices.py @@ -28,7 +28,9 @@ class SPIDevice(Device): """ def __init__(self, **spi_args): self._spi = None - super(SPIDevice, self).__init__() + super(SPIDevice, self).__init__( + pin_factory=spi_args.pop('pin_factory', None) + ) self._spi = self.pin_factory.spi(**spi_args) def close(self):