├── .gitignore ├── .stickler.yml ├── LICENSE ├── README.md ├── examples ├── control-main.py ├── keyboard.py ├── long-press.py ├── rainbow.py └── volume.py ├── library ├── CHANGELOG.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── buttonshim │ └── __init__.py ├── setup.py └── test.py ├── packaging ├── CHANGELOG ├── debian │ ├── README │ ├── changelog │ ├── clean │ ├── compat │ ├── control │ ├── copyright │ ├── docs │ ├── rules │ └── source │ │ ├── format │ │ └── options ├── makeall.sh ├── makedeb.sh ├── makedoc.sh └── makelog.sh └── sphinx ├── _static └── custom.css ├── _templates ├── breadcrumbs.html └── layout.html ├── conf.py ├── favicon.png ├── index.rst └── shop-logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | _build/ 3 | *.o 4 | *.so 5 | *.a 6 | *.py[cod] 7 | *.egg-info 8 | dist/ 9 | __pycache__ 10 | .DS_Store 11 | *.deb 12 | *.dsc 13 | *.build 14 | *.changes 15 | *.orig.* 16 | packaging/*tar.xz 17 | library/debian/ 18 | library/blinkt 19 | sphinx/Makefile 20 | -------------------------------------------------------------------------------- /.stickler.yml: -------------------------------------------------------------------------------- 1 | --- 2 | linters: 3 | flake8: 4 | python: 3 5 | max-line-length: 160 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pimoroni Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | https://shop.pimoroni.com/products/button-shim 2 | 3 | Five tactile push buttons and one super-bright RGB LED indicator, ideal for adding extra input and visual notifications to your Raspberry Pi alongside most other HATs and pHATs! 4 | 5 | ## Installing 6 | 7 | ### Full install (recommended): 8 | 9 | We've created an easy installation script that will install all pre-requisites and get your Buttom SHIM. 10 | up and running with minimal efforts. To run it, fire up Terminal which you'll find in Menu -> Accessories -> Terminal 11 | on your Raspberry Pi desktop, as illustrated below: 12 | 13 | ![Finding the terminal](http://get.pimoroni.com/resources/github-repo-terminal.png) 14 | 15 | In the new terminal window type the command exactly as it appears below (check for typos) and follow the on-screen instructions: 16 | 17 | ```bash 18 | curl https://get.pimoroni.com/buttonshim | bash 19 | ``` 20 | 21 | Alternatively, on Raspbian, you can download the `pimoroni-dashboard` and install your product by browsing to the relevant entry: 22 | 23 | ```bash 24 | sudo apt-get install pimoroni 25 | ``` 26 | (you will find the Dashboard under 'Accessories' too, in the Pi menu - or just run `pimoroni-dashboard` at the command line) 27 | 28 | If you choose to download examples you'll find them in `/home/pi/Pimoroni/buttonshim/`. 29 | 30 | ### Manual install: 31 | 32 | #### Library install for Python 3: 33 | 34 | on Raspbian: 35 | 36 | ```bash 37 | sudo apt-get install python3-buttonshim 38 | ``` 39 | 40 | other environments: 41 | 42 | ```bash 43 | sudo pip3 install buttonshim 44 | ``` 45 | 46 | #### Library install for Python 2: 47 | 48 | on Raspbian: 49 | 50 | ```bash 51 | sudo apt-get install python-buttonshim 52 | ``` 53 | 54 | other environments: 55 | 56 | ```bash 57 | sudo pip2 install buttonshim 58 | ``` 59 | 60 | ### Development: 61 | 62 | If you want to contribute, or like living on the edge of your seat by having the latest code, you should clone this repository, `cd` to the library directory, and run: 63 | 64 | ```bash 65 | sudo python3 setup.py install 66 | ``` 67 | (or `sudo python setup.py install` whichever your primary Python environment may be) 68 | 69 | ## Documentation & Support 70 | 71 | * Guides and tutorials - https://learn.pimoroni.com/button-shim 72 | * Function reference - http://docs.pimoroni.com/buttonshim/ 73 | * GPIO Pinout - https://pinout.xyz/pinout/button_shim 74 | * Get help - http://forums.pimoroni.com/c/support 75 | 76 | ## Unofficial / Third-party libraries 77 | 78 | * Go library by Tom Mitchell - https://github.com/tomnz/button-shim-go 79 | -------------------------------------------------------------------------------- /examples/control-main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import time 3 | import signal 4 | import buttonshim 5 | 6 | print(""" 7 | Button SHIM: control-main.py 8 | 9 | Light up the LED a different color of the rainbow with each button pressed. 10 | """) 11 | 12 | @buttonshim.on_press(buttonshim.BUTTON_A) 13 | def button_a(button, pressed): 14 | global button_flag 15 | button_flag = "button_1" 16 | 17 | @buttonshim.on_press(buttonshim.BUTTON_B) 18 | def button_b(button, pressed): 19 | global button_flag 20 | button_flag = "button_2" 21 | 22 | @buttonshim.on_press(buttonshim.BUTTON_C) 23 | def button_c(button, pressed): 24 | global button_flag 25 | button_flag = "button_3" 26 | 27 | @buttonshim.on_press(buttonshim.BUTTON_D) 28 | def button_d(button, pressed): 29 | global button_flag 30 | button_flag = "button_4" 31 | 32 | @buttonshim.on_press(buttonshim.BUTTON_E) 33 | def button_e(button, pressed): 34 | global button_flag 35 | button_flag = "button_5" 36 | 37 | button_flag = "null" 38 | 39 | while True: 40 | time.sleep(.1) 41 | if button_flag == "button_1": 42 | buttonshim.set_pixel(0x94, 0x00, 0xd3) 43 | button_flag = "null" 44 | elif button_flag == "button_2": 45 | buttonshim.set_pixel(0x00, 0x00, 0xff) 46 | button_flag = "null" 47 | elif button_flag == "button_3": 48 | buttonshim.set_pixel(0x00, 0xff, 0x00) 49 | button_flag = "null" 50 | elif button_flag == "button_4": 51 | buttonshim.set_pixel(0xff, 0xff, 0x00) 52 | button_flag = "null" 53 | elif button_flag == "button_5": 54 | buttonshim.set_pixel(0xff, 0x00, 0x00) 55 | button_flag = "null" -------------------------------------------------------------------------------- /examples/keyboard.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal 4 | import buttonshim 5 | import sys 6 | 7 | try: 8 | from evdev import uinput, UInput, ecodes as e 9 | except ImportError: 10 | exit("This library requires the evdev module\nInstall with: sudo pip install evdev") 11 | 12 | KEYCODES = [e.KEY_A, e.KEY_B, e.KEY_C, e.KEY_D, e.KEY_E] 13 | BUTTONS = [buttonshim.BUTTON_A, buttonshim.BUTTON_B, buttonshim.BUTTON_C, buttonshim.BUTTON_D, buttonshim.BUTTON_E] 14 | 15 | print(""" 16 | Button SHIM: keyboard.py 17 | 18 | Trigger keyboard key presses with Button SHIM. 19 | 20 | Press Ctrl+C to exit. 21 | 22 | """) 23 | 24 | try: 25 | ui = UInput({e.EV_KEY: KEYCODES}, name="Button-SHIM", bustype=e.BUS_USB) 26 | 27 | except uinput.UInputError as e: 28 | print(e.message) 29 | print("Have you tried running as root? sudo {}".format(sys.argv[0])) 30 | sys.exit(0) 31 | 32 | 33 | @buttonshim.on_press(BUTTONS) 34 | def button_p_handler(button, pressed): 35 | keycode = KEYCODES[button] 36 | print("Press: {}".format(keycode)) 37 | ui.write(e.EV_KEY, keycode, 1) 38 | ui.syn() 39 | 40 | 41 | @buttonshim.on_release(BUTTONS) 42 | def button_r_handler(button, pressed): 43 | keycode = KEYCODES[button] 44 | print("Release: {}".format(keycode)) 45 | ui.write(e.EV_KEY, keycode, 0) 46 | ui.syn() 47 | 48 | 49 | signal.pause() 50 | -------------------------------------------------------------------------------- /examples/long-press.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal 4 | import buttonshim 5 | 6 | 7 | print(""" 8 | Buttom SHIM: Long Press 9 | 10 | Demonstrates how you might handle both a 11 | short and long press on the same button. 12 | 13 | Press or hold the A button. 14 | 15 | Press Ctrl+C to exit! 16 | 17 | """) 18 | 19 | 20 | button_was_held = False 21 | 22 | 23 | @buttonshim.on_press(buttonshim.BUTTON_A) 24 | def press_handler(button, pressed): 25 | global button_was_held # So we change the global var defined above 26 | button_was_held = False # Reset the button held state 27 | 28 | 29 | @buttonshim.on_release(buttonshim.BUTTON_A) 30 | def release_handler(button, pressed): 31 | if not button_was_held: 32 | print("Short press detected!") 33 | 34 | 35 | @buttonshim.on_hold(buttonshim.BUTTON_A, hold_time=2) 36 | def hold_handler(button): 37 | global button_was_held 38 | button_was_held = True 39 | print("Long press detected!") 40 | 41 | 42 | signal.pause() # Stop script from immediately exiting 43 | -------------------------------------------------------------------------------- /examples/rainbow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal 4 | import buttonshim 5 | 6 | print(""" 7 | Button SHIM: rainbow.py 8 | 9 | Light up the LED a different colour of the rainbow with each button pressed. 10 | 11 | Press Ctrl+C to exit. 12 | 13 | """) 14 | 15 | 16 | @buttonshim.on_press(buttonshim.BUTTON_A) 17 | def button_a(button, pressed): 18 | buttonshim.set_pixel(0x94, 0x00, 0xd3) 19 | 20 | 21 | @buttonshim.on_press(buttonshim.BUTTON_B) 22 | def button_b(button, pressed): 23 | buttonshim.set_pixel(0x00, 0x00, 0xff) 24 | 25 | 26 | @buttonshim.on_press(buttonshim.BUTTON_C) 27 | def button_c(button, pressed): 28 | buttonshim.set_pixel(0x00, 0xff, 0x00) 29 | 30 | 31 | @buttonshim.on_press(buttonshim.BUTTON_D) 32 | def button_d(button, pressed): 33 | buttonshim.set_pixel(0xff, 0xff, 0x00) 34 | 35 | 36 | @buttonshim.on_press(buttonshim.BUTTON_E) 37 | def button_e(button, pressed): 38 | buttonshim.set_pixel(0xff, 0x00, 0x00) 39 | 40 | 41 | signal.pause() 42 | -------------------------------------------------------------------------------- /examples/volume.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import signal 4 | import buttonshim 5 | import subprocess 6 | import time 7 | from sys import version_info 8 | 9 | DEVICE = "PCM" 10 | VOL_REPEAT = 0.2 11 | 12 | print(""" 13 | Button SHIM: volume.py 14 | 15 | Control the audio volume on your Raspberry Pi! 16 | 17 | A = Unmute 18 | B = Mute 19 | C = Volume Up 20 | D = Volume Down 21 | E = Hold to power off 22 | 23 | Press Ctrl+C to exit. 24 | 25 | """) 26 | 27 | volume = 0 28 | 29 | 30 | def set(action): 31 | subprocess.Popen( 32 | ["amixer", "set", DEVICE, action], 33 | stdout=subprocess.PIPE, stderr=subprocess.PIPE) 34 | 35 | 36 | def get_volume(): 37 | actual_volume = subprocess.check_output( 38 | "amixer get '{}' | awk '$0~/%/{{print $4}}' | tr -d '[]%'".format(DEVICE), 39 | shell=True) 40 | 41 | if version_info[0] >= 3: 42 | actual_volume = actual_volume.strip().decode('utf-8') 43 | else: 44 | actual_volume = actual_volume.strip() 45 | 46 | actual_volume = int(actual_volume) 47 | actual_volume = min(100, actual_volume) 48 | actual_volume = max(0, actual_volume) 49 | 50 | return actual_volume 51 | 52 | 53 | # Unmute 54 | @buttonshim.on_press(buttonshim.BUTTON_A) 55 | def button_a(button, pressed): 56 | global volume 57 | 58 | print("Status: Unmute") 59 | set("unmute") 60 | 61 | volume = get_volume() 62 | scale = volume / 100.0 63 | 64 | buttonshim.set_pixel(int(0xff * (1.0 - scale)), int(0xff * scale), 0x00) 65 | 66 | 67 | # Mute 68 | @buttonshim.on_press(buttonshim.BUTTON_B) 69 | def button_b(button, pressed): 70 | print("Status: Mute") 71 | set("mute") 72 | 73 | buttonshim.set_pixel(0xff, 0x00, 0x00) 74 | 75 | 76 | # Volume Up 77 | @buttonshim.on_press(buttonshim.BUTTON_C, repeat=True, repeat_time=VOL_REPEAT) 78 | def button_c(button, pressed): 79 | global volume 80 | 81 | volume = get_volume() 82 | volume += 1 83 | volume = min(100, volume) 84 | 85 | print("Volume: {}%".format(volume)) 86 | set("{}%".format(volume)) 87 | 88 | scale = volume / 100.0 89 | 90 | buttonshim.set_pixel(int(0xff * (1.0 - scale)), int(0xff * scale), 0x00) 91 | 92 | 93 | # Volume Down 94 | @buttonshim.on_press(buttonshim.BUTTON_D, repeat=True, repeat_time=VOL_REPEAT) 95 | def button_d(button, pressed): 96 | global volume 97 | 98 | volume = get_volume() 99 | volume -= 1 100 | volume = max(0, volume) 101 | 102 | print("Volume: {}%".format(volume)) 103 | set("{}%".format(volume)) 104 | 105 | scale = volume / 100.0 106 | 107 | buttonshim.set_pixel(int(0xff * (1.0 - scale)), int(0xff * scale), 0x00) 108 | 109 | 110 | # Soft Power Off? 111 | @buttonshim.on_press(buttonshim.BUTTON_E) 112 | def button_e_press(button, pressed): 113 | buttonshim.set_pixel(0xff, 0x00, 0x00) 114 | 115 | 116 | @buttonshim.on_hold(buttonshim.BUTTON_E, hold_time=2) 117 | def button_e(button): 118 | print("Held for 2sec!") 119 | time.sleep(0.1) 120 | for x in range(3): 121 | buttonshim.set_pixel(0xff, 0x00, 0x00) 122 | time.sleep(0.1) 123 | buttonshim.set_pixel(0x00, 0x00, 0x00) 124 | time.sleep(0.1) 125 | 126 | 127 | signal.pause() 128 | -------------------------------------------------------------------------------- /library/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | 0.0.2 2 | ----- 3 | 4 | * Fix: Deferred setup to prevent import side-effects 5 | * Fix: Corrected NUM_BUTTONS to 5 from 6 6 | 7 | 0.0.1 8 | ----- 9 | 10 | * Initial version 11 | 12 | -------------------------------------------------------------------------------- /library/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Pimoroni Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /library/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGELOG.txt 2 | include LICENSE.txt 3 | include README.rst 4 | include setup.py 5 | recursive-include buttonshim *.py 6 | -------------------------------------------------------------------------------- /library/README.rst: -------------------------------------------------------------------------------- 1 | https://shop.pimoroni.com/products/button-shim 2 | 3 | Five tactile push buttons and one super-bright RGB LED indicator, ideal 4 | for adding extra input and visual notifications to your Raspberry Pi 5 | alongside most other HATs and pHATs! 6 | 7 | Installing 8 | ---------- 9 | 10 | Full install (recommended): 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 | 13 | We've created an easy installation script that will install all 14 | pre-requisites and get your Buttom SHIM. up and running with minimal 15 | efforts. To run it, fire up Terminal which you'll find in Menu -> 16 | Accessories -> Terminal on your Raspberry Pi desktop, as illustrated 17 | below: 18 | 19 | .. figure:: http://get.pimoroni.com/resources/github-repo-terminal.png 20 | :alt: Finding the terminal 21 | 22 | In the new terminal window type the command exactly as it appears below 23 | (check for typos) and follow the on-screen instructions: 24 | 25 | .. code:: bash 26 | 27 | curl https://get.pimoroni.com/buttonshim | bash 28 | 29 | Alternatively, on Raspbian, you can download the ``pimoroni-dashboard`` 30 | and install your product by browsing to the relevant entry: 31 | 32 | .. code:: bash 33 | 34 | sudo apt-get install pimoroni 35 | 36 | (you will find the Dashboard under 'Accessories' too, in the Pi menu - 37 | or just run ``pimoroni-dashboard`` at the command line) 38 | 39 | If you choose to download examples you'll find them in 40 | ``/home/pi/Pimoroni/buttonshim/``. 41 | 42 | Manual install: 43 | ~~~~~~~~~~~~~~~ 44 | 45 | Library install for Python 3: 46 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 47 | 48 | on Raspbian: 49 | 50 | .. code:: bash 51 | 52 | sudo apt-get install python3-buttonshim 53 | 54 | other environments: 55 | 56 | .. code:: bash 57 | 58 | sudo pip3 install buttonshim 59 | 60 | Library install for Python 2: 61 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 62 | 63 | on Raspbian: 64 | 65 | .. code:: bash 66 | 67 | sudo apt-get install python-buttonshim 68 | 69 | other environments: 70 | 71 | .. code:: bash 72 | 73 | sudo pip2 install buttonshim 74 | 75 | Development: 76 | ~~~~~~~~~~~~ 77 | 78 | If you want to contribute, or like living on the edge of your seat by 79 | having the latest code, you should clone this repository, ``cd`` to the 80 | library directory, and run: 81 | 82 | .. code:: bash 83 | 84 | sudo python3 setup.py install 85 | 86 | (or ``sudo python setup.py install`` whichever your primary Python 87 | environment may be) 88 | 89 | Documentation & Support 90 | ----------------------- 91 | 92 | - Guides and tutorials - https://learn.pimoroni.com/button-shim 93 | - Function reference - http://docs.pimoroni.com/buttonshim/ 94 | - GPIO Pinout - https://pinout.xyz/pinout/buttonshim 95 | - Get help - http://forums.pimoroni.com/c/support 96 | 97 | Unofficial / Third-party libraries 98 | ---------------------------------- 99 | 100 | - Go library by Tom Mitchell - https://github.com/tomnz/button-shim-go 101 | -------------------------------------------------------------------------------- /library/buttonshim/__init__.py: -------------------------------------------------------------------------------- 1 | import smbus 2 | import time 3 | from threading import Thread 4 | import atexit 5 | from colorsys import hsv_to_rgb 6 | 7 | try: 8 | import queue 9 | except ImportError: 10 | import Queue as queue 11 | 12 | ADDR = 0x3f 13 | 14 | __version__ = '0.0.2' 15 | 16 | _bus = None 17 | 18 | LED_DATA = 7 19 | LED_CLOCK = 6 20 | 21 | REG_INPUT = 0x00 22 | REG_OUTPUT = 0x01 23 | REG_POLARITY = 0x02 24 | REG_CONFIG = 0x03 25 | 26 | NUM_BUTTONS = 5 27 | 28 | BUTTON_A = 0 29 | """Button A""" 30 | BUTTON_B = 1 31 | """Button B""" 32 | BUTTON_C = 2 33 | """Button C""" 34 | BUTTON_D = 3 35 | """Button D""" 36 | BUTTON_E = 4 37 | """Button E""" 38 | 39 | NAMES = ['A', 'B', 'C', 'D', 'E'] 40 | """Sometimes you want to print the plain text name of the button that's triggered. 41 | 42 | You can use:: 43 | 44 | buttonshim.NAMES[button_index] 45 | 46 | To accomplish this. 47 | 48 | """ 49 | 50 | ERROR_LIMIT = 10 51 | 52 | FPS = 60 53 | 54 | LED_GAMMA = [ 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 57 | 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 58 | 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 59 | 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 60 | 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, 61 | 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 62 | 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 63 | 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 64 | 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 65 | 90, 91, 93, 94, 95, 96, 98, 99, 100, 102, 103, 104, 106, 107, 109, 110, 66 | 111, 113, 114, 116, 117, 119, 120, 121, 123, 124, 126, 128, 129, 131, 132, 134, 67 | 135, 137, 138, 140, 142, 143, 145, 146, 148, 150, 151, 153, 155, 157, 158, 160, 68 | 162, 163, 165, 167, 169, 170, 172, 174, 176, 178, 179, 181, 183, 185, 187, 189, 69 | 191, 193, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 70 | 222, 224, 227, 229, 231, 233, 235, 237, 239, 241, 244, 246, 248, 250, 252, 255] 71 | 72 | # The LED is an APA102 driven via the i2c IO expander. 73 | # We must set and clear the Clock and Data pins 74 | # Each byte in _reg_queue represents a snapshot of the pin state 75 | 76 | _reg_queue = [] 77 | _update_queue = [] 78 | _brightness = 0.5 79 | 80 | _led_queue = queue.Queue() 81 | 82 | _t_poll = None 83 | 84 | _running = False 85 | 86 | _states = 0b00011111 87 | 88 | 89 | class Handler(): 90 | def __init__(self): 91 | self.press = None 92 | self.release = None 93 | 94 | self.hold = None 95 | self.hold_time = 0 96 | 97 | self.repeat = False 98 | self.repeat_time = 0 99 | 100 | self.t_pressed = 0 101 | self.t_repeat = 0 102 | self.hold_fired = False 103 | 104 | 105 | _handlers = [Handler() for x in range(NUM_BUTTONS)] 106 | 107 | 108 | def _run(): 109 | global _running, _states 110 | _running = True 111 | _last_states = 0b00011111 112 | _errors = 0 113 | 114 | while _running: 115 | led_data = None 116 | 117 | try: 118 | led_data = _led_queue.get(False) 119 | _led_queue.task_done() 120 | 121 | except queue.Empty: 122 | pass 123 | 124 | try: 125 | if led_data: 126 | for chunk in _chunk(led_data, 32): 127 | _bus.write_i2c_block_data(ADDR, REG_OUTPUT, chunk) 128 | 129 | _states = _bus.read_byte_data(ADDR, REG_INPUT) 130 | 131 | except IOError: 132 | _errors += 1 133 | if _errors > ERROR_LIMIT: 134 | _running = False 135 | raise IOError("More than {} IO errors have occurred!".format(ERROR_LIMIT)) 136 | 137 | for x in range(NUM_BUTTONS): 138 | last = (_last_states >> x) & 1 139 | curr = (_states >> x) & 1 140 | handler = _handlers[x] 141 | 142 | # If last > curr then it's a transition from 1 to 0 143 | # since the buttons are active low, that's a press event 144 | if last > curr: 145 | handler.t_pressed = time.time() 146 | handler.hold_fired = False 147 | 148 | if callable(handler.press): 149 | handler.t_repeat = time.time() 150 | Thread(target=handler.press, args=(x, True)).start() 151 | 152 | continue 153 | 154 | if last < curr and callable(handler.release): 155 | Thread(target=handler.release, args=(x, False)).start() 156 | continue 157 | 158 | if curr == 0: 159 | if callable(handler.hold) and not handler.hold_fired and (time.time() - handler.t_pressed) > handler.hold_time: 160 | Thread(target=handler.hold, args=(x,)).start() 161 | handler.hold_fired = True 162 | 163 | if handler.repeat and callable(handler.press) and (time.time() - handler.t_repeat) > handler.repeat_time: 164 | _handlers[x].t_repeat = time.time() 165 | Thread(target=_handlers[x].press, args=(x, True)).start() 166 | 167 | _last_states = _states 168 | 169 | time.sleep(1.0 / FPS) 170 | 171 | 172 | def _quit(): 173 | global _running 174 | 175 | if _running: 176 | _led_queue.join() 177 | set_pixel(0, 0, 0) 178 | _led_queue.join() 179 | 180 | _running = False 181 | _t_poll.join() 182 | 183 | 184 | def setup(): 185 | global _t_poll, _bus 186 | 187 | if _bus is not None: 188 | return 189 | 190 | _bus = smbus.SMBus(1) 191 | 192 | _bus.write_byte_data(ADDR, REG_CONFIG, 0b00011111) 193 | _bus.write_byte_data(ADDR, REG_POLARITY, 0b00000000) 194 | _bus.write_byte_data(ADDR, REG_OUTPUT, 0b00000000) 195 | 196 | _t_poll = Thread(target=_run) 197 | _t_poll.daemon = True 198 | _t_poll.start() 199 | 200 | set_pixel(0, 0, 0) 201 | 202 | atexit.register(_quit) 203 | 204 | 205 | def _set_bit(pin, value): 206 | global _reg_queue 207 | 208 | if value: 209 | _reg_queue[-1] |= (1 << pin) 210 | else: 211 | _reg_queue[-1] &= ~(1 << pin) 212 | 213 | 214 | def _next(): 215 | global _reg_queue 216 | 217 | if len(_reg_queue) == 0: 218 | _reg_queue = [0b00000000] 219 | else: 220 | _reg_queue.append(_reg_queue[-1]) 221 | 222 | 223 | def _enqueue(): 224 | global _reg_queue 225 | 226 | _led_queue.put(_reg_queue) 227 | 228 | _reg_queue = [] 229 | 230 | 231 | def _chunk(l, n): 232 | for i in range(0, len(l)+1, n): 233 | yield l[i:i + n] 234 | 235 | 236 | def _write_byte(byte): 237 | for x in range(8): 238 | _next() 239 | _set_bit(LED_CLOCK, 0) 240 | _set_bit(LED_DATA, byte & 0b10000000) 241 | _next() 242 | _set_bit(LED_CLOCK, 1) 243 | byte <<= 1 244 | 245 | 246 | def on_hold(buttons, handler=None, hold_time=2): 247 | """Attach a hold handler to one or more buttons. 248 | 249 | This handler is fired when you hold a button for hold_time seconds. 250 | 251 | When fired it will run in its own Thread. 252 | 253 | It will be passed one argument, the button index:: 254 | 255 | @buttonshim.on_hold(buttonshim.BUTTON_A) 256 | def handler(button): 257 | # Your code here 258 | 259 | :param buttons: A single button, or a list of buttons 260 | :param handler: Optional: a function to bind as the handler 261 | :param hold_time: Optional: the hold time in seconds (default 2) 262 | 263 | """ 264 | setup() 265 | 266 | if buttons is None: 267 | buttons = [BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D, BUTTON_E] 268 | 269 | if isinstance(buttons, int): 270 | buttons = [buttons] 271 | 272 | def attach_handler(handler): 273 | for button in buttons: 274 | _handlers[button].hold = handler 275 | _handlers[button].hold_time = hold_time 276 | 277 | if handler is not None: 278 | attach_handler(handler) 279 | else: 280 | return attach_handler 281 | 282 | 283 | def on_press(buttons, handler=None, repeat=False, repeat_time=0.5): 284 | """Attach a press handler to one or more buttons. 285 | 286 | This handler is fired when you press a button. 287 | 288 | When fired it will be run in its own Thread. 289 | 290 | It will be passed two arguments, the button index and a 291 | boolean indicating whether the button has been pressed/released:: 292 | 293 | @buttonshim.on_press(buttonshim.BUTTON_A) 294 | def handler(button, pressed): 295 | # Your code here 296 | 297 | :param buttons: A single button, or a list of buttons 298 | :param handler: Optional: a function to bind as the handler 299 | :param repeat: Optional: Repeat the handler if the button is held 300 | :param repeat_time: Optional: Time, in seconds, after which to repeat 301 | 302 | """ 303 | setup() 304 | 305 | if buttons is None: 306 | buttons = [BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D, BUTTON_E] 307 | 308 | if isinstance(buttons, int): 309 | buttons = [buttons] 310 | 311 | def attach_handler(handler): 312 | for button in buttons: 313 | _handlers[button].press = handler 314 | _handlers[button].repeat = repeat 315 | _handlers[button].repeat_time = repeat_time 316 | 317 | if handler is not None: 318 | attach_handler(handler) 319 | else: 320 | return attach_handler 321 | 322 | 323 | def on_release(buttons=None, handler=None): 324 | """Attach a release handler to one or more buttons. 325 | 326 | This handler is fired when you let go of a button. 327 | 328 | When fired it will be run in its own Thread. 329 | 330 | It will be passed two arguments, the button index and a 331 | boolean indicating whether the button has been pressed/released:: 332 | 333 | @buttonshim.on_release(buttonshim.BUTTON_A) 334 | def handler(button, pressed): 335 | # Your code here 336 | 337 | :param buttons: A single button, or a list of buttons 338 | :param handler: Optional: a function to bind as the handler 339 | 340 | """ 341 | setup() 342 | 343 | if buttons is None: 344 | buttons = [BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D, BUTTON_E] 345 | 346 | if isinstance(buttons, int): 347 | buttons = [buttons] 348 | 349 | def attach_handler(handler): 350 | for button in buttons: 351 | _handlers[button].release = handler 352 | 353 | if handler is not None: 354 | attach_handler(handler) 355 | else: 356 | return attach_handler 357 | 358 | 359 | def set_brightness(brightness): 360 | global _brightness 361 | 362 | setup() 363 | 364 | if not isinstance(brightness, int) and not isinstance(brightness, float): 365 | raise ValueError("Brightness should be an int or float") 366 | 367 | if brightness < 0.0 or brightness > 1.0: 368 | raise ValueError("Brightness should be between 0.0 and 1.0") 369 | 370 | _brightness = brightness 371 | 372 | 373 | def set_pixel(r, g, b): 374 | """Set the Button SHIM RGB pixel 375 | 376 | Display an RGB colour on the Button SHIM pixel. 377 | 378 | :param r: Amount of red, from 0 to 255 379 | :param g: Amount of green, from 0 to 255 380 | :param b: Amount of blue, from 0 to 255 381 | 382 | You can use HTML colours directly with hexadecimal notation in Python. EG:: 383 | 384 | buttonshim.set_pixel(0xFF, 0x00, 0xFF) 385 | 386 | """ 387 | setup() 388 | 389 | if not isinstance(r, int) or r < 0 or r > 255: 390 | raise ValueError("Argument r should be an int from 0 to 255") 391 | 392 | if not isinstance(g, int) or g < 0 or g > 255: 393 | raise ValueError("Argument g should be an int from 0 to 255") 394 | 395 | if not isinstance(b, int) or b < 0 or b > 255: 396 | raise ValueError("Argument b should be an int from 0 to 255") 397 | 398 | r, g, b = [int(x * _brightness) for x in (r, g, b)] 399 | 400 | _write_byte(0) 401 | _write_byte(0) 402 | _write_byte(0b11101111) 403 | _write_byte(LED_GAMMA[b & 0xff]) 404 | _write_byte(LED_GAMMA[g & 0xff]) 405 | _write_byte(LED_GAMMA[r & 0xff]) 406 | _write_byte(0) 407 | _write_byte(0) 408 | _enqueue() 409 | 410 | 411 | if __name__ == "__main__": 412 | @on_press([BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D, BUTTON_E]) 413 | def handle_press(button, state): 414 | print("PRESS: Button {} ({}) is {}".format(button, NAMES[button], state)) 415 | 416 | @on_release([BUTTON_A, BUTTON_B, BUTTON_C, BUTTON_D, BUTTON_E]) 417 | def handle_release(button, state): 418 | print("RELEASE: Button {} ({}) is {}".format(button, NAMES[button], state)) 419 | 420 | while True: 421 | hue = (time.time() * 100 % 360) / 360.0 422 | r, g, b = [int(c * 255) for c in hsv_to_rgb(hue, 1.0, 1.0)] 423 | 424 | set_pixel(r, g, b) 425 | 426 | time.sleep(0.1) 427 | -------------------------------------------------------------------------------- /library/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Copyright (c) 2017 Pimoroni 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | of the Software, and to permit persons to whom the Software is furnished to do 11 | so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | """ 24 | 25 | try: 26 | from setuptools import setup 27 | except ImportError: 28 | from distutils.core import setup 29 | 30 | classifiers = ['Development Status :: 5 - Production/Stable', 31 | 'Operating System :: POSIX :: Linux', 32 | 'License :: OSI Approved :: MIT License', 33 | 'Intended Audience :: Developers', 34 | 'Programming Language :: Python :: 2.6', 35 | 'Programming Language :: Python :: 2.7', 36 | 'Programming Language :: Python :: 3', 37 | 'Topic :: Software Development', 38 | 'Topic :: System :: Hardware'] 39 | 40 | setup( 41 | name = 'buttonshim', 42 | version = '0.0.2', 43 | author = 'Philip Howard', 44 | author_email = 'phil@pimoroni.com', 45 | description = 'Button SHIM Driver', 46 | long_description= open('README.rst').read() + "\n" + open('CHANGELOG.txt').read(), 47 | license = 'MIT', 48 | keywords = 'Raspberry Pi LED', 49 | url = 'http://www.pimoroni.com', 50 | classifiers = classifiers, 51 | py_modules = [], 52 | packages = ['buttonshim'], 53 | include_package_data = True, 54 | install_requires= [] 55 | ) 56 | -------------------------------------------------------------------------------- /library/test.py: -------------------------------------------------------------------------------- 1 | import mock 2 | import sys 3 | 4 | REG_INPUT = 0x00 5 | REG_OUTPUT = 0x01 6 | REG_POLARITY = 0x02 7 | REG_CONFIG = 0x03 8 | 9 | regs = [0 for x in range(4)] 10 | 11 | class SMBus: 12 | def __init__(self, bus_id): 13 | global regs 14 | 15 | regs[REG_INPUT] = 0 # 0x00: REG_INPUT 16 | regs[REG_OUTPUT] = 0 # 0x01: REG_OUTPUT 17 | regs[REG_POLARITY] = 0 # 0x02: REG_POLARITY 18 | regs[REG_CONFIG] = 0 # 0x03: REG_CONFIG 19 | 20 | self._watch_regs = { 21 | REG_INPUT: 'REG_INPUT', 22 | REG_OUTPUT: 'REG_OUTPUT', 23 | REG_POLARITY: 'REG_POLARITY', 24 | REG_CONFIG: 'REG_CONFIG' 25 | } 26 | 27 | self._watch_len = { 28 | REG_INPUT: 1, 29 | REG_OUTPUT: 1, 30 | REG_POLARITY: 1, 31 | REG_CONFIG: 1 32 | } 33 | 34 | def _debug(self, addr, reg, data): 35 | global regs 36 | 37 | if reg in self._watch_regs.keys(): 38 | name = self._watch_regs[reg] 39 | length = self._watch_len[reg] 40 | result = regs[reg:reg+length] 41 | print("Writing {data} to {name}: {result}".format( 42 | data=data, addr=addr, reg=reg, name=name, result=result)) 43 | 44 | def write_i2c_block_data(self, addr, reg, data): 45 | global regs 46 | 47 | self._debug(addr, reg, data) 48 | 49 | for index, value in enumerate(data): 50 | regs[reg] = value 51 | 52 | def write_word_data(self, addr, reg, data): 53 | global regs 54 | 55 | regs[reg] = (data >> 8) & 0xff 56 | regs[reg + 1] = data & 0xff 57 | self._debug(addr, reg, data) 58 | 59 | def write_byte_data(self, addr, reg, data): 60 | global regs 61 | 62 | regs[reg] = data & 0xff 63 | 64 | self._debug(addr, reg, data) 65 | 66 | def read_byte_data(self, addr, reg): 67 | global regs 68 | 69 | return regs[reg] 70 | 71 | def read_word_data(self, addr, reg): 72 | global regs 73 | 74 | return (regs[reg] << 8) | regs[reg + 1] 75 | 76 | 77 | def i2c_assert(action, expect, message): 78 | action() 79 | assert expect(), message 80 | 81 | def assert_raises(action, expect, message): 82 | try: 83 | action() 84 | except expect: 85 | return 86 | 87 | print(message) 88 | sys.exit(1) 89 | 90 | 91 | smbus = mock.Mock() 92 | smbus.SMBus = SMBus 93 | 94 | sys.modules['smbus'] = smbus 95 | sys.path.insert(0, ".") 96 | 97 | import buttonshim 98 | 99 | @buttonshim.on_press(buttonshim.BUTTON_A) 100 | def press(button, state): 101 | pass 102 | 103 | assert regs[REG_CONFIG] == 31, "REG_CONFIG should be set to 31" 104 | assert regs[REG_POLARITY] == 0, "REG_POLARITY should be set to 0" 105 | assert regs[REG_OUTPUT] == 0, "REG_OUTPUT should be set to 0" 106 | 107 | assert_raises(lambda: buttonshim.set_pixel("", "", ""), 108 | ValueError, "set_pixel does not raise ValueError if r/g/b not int") 109 | 110 | assert_raises(lambda: buttonshim.set_pixel(-1, -1, -1), 111 | ValueError, "set_pixel does not raise ValueError if r/g/b < -1") 112 | 113 | assert_raises(lambda: buttonshim.set_pixel(256, 256, 256), 114 | ValueError, "set_pixel does not raise ValueError if r/g/b > 255") 115 | 116 | i2c_assert(lambda: buttonshim.set_pixel(0, 0, 0), 117 | lambda: regs[REG_OUTPUT] == 00, 118 | "REG_OUTPUT should equal 0") 119 | -------------------------------------------------------------------------------- /packaging/CHANGELOG: -------------------------------------------------------------------------------- 1 | buttonshim (0.0.2) stable; urgency=low 2 | 3 | * Fix: Deferred setup to prevent import side-effects 4 | * Fix: Corrected NUM_BUTTONS to 5 from 6 5 | 6 | -- Phil Howard Wed, 28 Feb 2018 00:00:00 +0000 7 | 8 | buttonshim (0.0.1) stable; urgency=low 9 | 10 | * Initial version 11 | 12 | -- Phil Howard Mon, 31 Jul 2017 00:00:00 +0000 13 | -------------------------------------------------------------------------------- /packaging/debian/README: -------------------------------------------------------------------------------- 1 | README 2 | 3 | Button SHIM provides one super-bright RGB LED indicator and 5 buttons. Ideal for adding input to your Raspberry Pi project. 4 | 5 | Learn more: https://shop.pimoroni.com/products/button-shim 6 | For examples run: `curl -sS get.pimoroni.com/button-shim | bash` 7 | -------------------------------------------------------------------------------- /packaging/debian/changelog: -------------------------------------------------------------------------------- 1 | buttonshim (0.0.2) stable; urgency=low 2 | 3 | * Fix: Deferred setup to prevent import side-effects 4 | * Fix: Corrected NUM_BUTTONS to 5 from 6 5 | 6 | -- Phil Howard Wed, 28 Feb 2018 00:00:00 +0000 7 | 8 | buttonshim (0.0.1) stable; urgency=low 9 | 10 | * Initial version 11 | 12 | -- Phil Howard Mon, 31 Jul 2017 00:00:00 +0000 13 | -------------------------------------------------------------------------------- /packaging/debian/clean: -------------------------------------------------------------------------------- 1 | *.egg-info/* 2 | -------------------------------------------------------------------------------- /packaging/debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /packaging/debian/control: -------------------------------------------------------------------------------- 1 | Source: buttonshim 2 | Maintainer: Phil Howard 3 | Homepage: https://github.com/pimoroni/button-shim 4 | Section: python 5 | Priority: extra 6 | Build-Depends: debhelper (>= 9.0.0), dh-python, python-all (>= 2.7), python-setuptools, python3-all (>= 3.4), python3-setuptools 7 | Standards-Version: 3.9.6 8 | X-Python-Version: >= 2.7 9 | X-Python3-Version: >= 3.4 10 | 11 | Package: python-buttonshim 12 | Architecture: all 13 | Section: python 14 | Depends: ${misc:Depends}, ${python:Depends}, python-smbus 15 | Suggests: python-psutil, python-requests 16 | Description: Python library for the Pimoroni Button SHIM 17 | Button SHIM provides one super-bright RGB LED indicator and 5 buttons. 18 | Ideal for adding input to your Raspberry Pi project. 19 | . 20 | This is the Python 2 version of the package. 21 | 22 | Package: python3-buttonshim 23 | Architecture: all 24 | Section: python 25 | Depends: ${misc:Depends}, ${python3:Depends}, python3-smbus 26 | Suggests: python3-psutil, python3-requests 27 | Description: Python library for the Pimoroni Button SHIM 28 | Button SHIM provides one super-bright RGB LED indicator and 5 buttons. 29 | Ideal for adding input to your Raspberry Pi project. 30 | . 31 | This is the Python 3 version of the package. 32 | -------------------------------------------------------------------------------- /packaging/debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: buttonshim 3 | Source: https://github.com/pimoroni/button-shim 4 | 5 | Files: * 6 | Copyright: 2016 Pimoroni Ltd 7 | License: MIT 8 | 9 | License: MIT 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | . 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | . 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | -------------------------------------------------------------------------------- /packaging/debian/docs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pimoroni/button-shim/fce7b220e3a09fa89e8389a94d81e1bc6974d94e/packaging/debian/docs -------------------------------------------------------------------------------- /packaging/debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | 4 | #export DH_VERBOSE=1 5 | export DH_OPTIONS 6 | 7 | %: 8 | dh $@ --with python2,python3 --buildsystem=python_distutils 9 | 10 | override_dh_auto_install: 11 | python setup.py install --root debian/python-buttonshim --install-layout=deb 12 | python3 setup.py install --root debian/python3-buttonshim --install-layout=deb 13 | -------------------------------------------------------------------------------- /packaging/debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /packaging/debian/source/options: -------------------------------------------------------------------------------- 1 | extend-diff-ignore = "^[^/]+\.egg-info/" 2 | -------------------------------------------------------------------------------- /packaging/makeall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # script control variables 4 | 5 | reponame="" # leave this blank for auto-detection 6 | libname="" # leave this blank for auto-detection 7 | packagename="" # leave this blank for auto-selection 8 | 9 | debianlog="debian/changelog" 10 | debcontrol="debian/control" 11 | debcopyright="debian/copyright" 12 | debrules="debian/rules" 13 | debreadme="debian/README" 14 | 15 | debdir="$(pwd)" 16 | rootdir="$(dirname $debdir)" 17 | libdir="$rootdir/library" 18 | 19 | FLAG=false 20 | 21 | # function define 22 | 23 | success() { 24 | echo "$(tput setaf 2)$1$(tput sgr0)" 25 | } 26 | 27 | inform() { 28 | echo "$(tput setaf 6)$1$(tput sgr0)" 29 | } 30 | 31 | warning() { 32 | echo "$(tput setaf 1)$1$(tput sgr0)" 33 | } 34 | 35 | newline() { 36 | echo "" 37 | } 38 | 39 | # assessing repo and library variables 40 | 41 | if [ -z "$reponame" ] || [ -z "$libname" ]; then 42 | inform "detecting reponame and libname..." 43 | else 44 | inform "using reponame and libname overrides" 45 | fi 46 | 47 | if [ -z "$reponame" ]; then 48 | if [[ $rootdir == *"python"* ]]; then 49 | repodir="$(dirname $rootdir)" 50 | reponame="$(basename $repodir)" 51 | else 52 | repodir="$rootdir" 53 | reponame="$(basename $repodir)" 54 | fi 55 | reponame=$(echo "$reponame" | tr "[A-Z]" "[a-z]") 56 | fi 57 | 58 | if [ -z "$libname" ]; then 59 | cd "$libdir" 60 | libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev) 61 | libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir" 62 | fi 63 | 64 | if [ -z "$packagename" ]; then 65 | packagename="$libname" 66 | fi 67 | 68 | echo "reponame is $reponame and libname is $libname" 69 | echo "output packages will be python-$packagename and python3-$packagename" 70 | 71 | # checking generating changelog file 72 | 73 | ./makelog.sh 74 | version=$(head -n 1 "$libdir/CHANGELOG.txt") 75 | echo "building $libname version $version" 76 | 77 | # checking debian/changelog file 78 | 79 | inform "checking debian/changelog file..." 80 | 81 | if ! head -n 1 $debianlog | grep "$libname" &> /dev/null; then 82 | warning "library not mentioned in header!" && FLAG=true 83 | elif head -n 1 $debianlog | grep "UNRELEASED"; then 84 | warning "this changelog is not going to generate a release!" 85 | warning "change distribution to 'stable'" && FLAG=true 86 | fi 87 | 88 | # checking debian/copyright file 89 | 90 | inform "checking debian/copyright file..." 91 | 92 | if ! grep "^Source" $debcopyright | grep "$reponame" &> /dev/null; then 93 | warning "$(grep "^Source" $debcopyright)" && FLAG=true 94 | fi 95 | 96 | if ! grep "^Upstream-Name" $debcopyright | grep "$libname" &> /dev/null; then 97 | warning "$(grep "^Upstream-Name" $debcopyright)" && FLAG=true 98 | fi 99 | 100 | # checking debian/control file 101 | 102 | inform "checking debian/control file..." 103 | 104 | if ! grep "^Source" $debcontrol | grep "$libname" &> /dev/null; then 105 | warning "$(grep "^Source" $debcontrol)" && FLAG=true 106 | fi 107 | 108 | if ! grep "^Homepage" $debcontrol | grep "$reponame" &> /dev/null; then 109 | warning "$(grep "^Homepage" $debcontrol)" && FLAG=true 110 | fi 111 | 112 | if ! grep "^Package: python-$packagename" $debcontrol &> /dev/null; then 113 | warning "$(grep "^Package: python-" $debcontrol)" && FLAG=true 114 | fi 115 | 116 | if ! grep "^Package: python3-$packagename" $debcontrol &> /dev/null; then 117 | warning "$(grep "^Package: python3-" $debcontrol)" && FLAG=true 118 | fi 119 | 120 | if ! grep "^Priority: extra" $debcontrol &> /dev/null; then 121 | warning "$(grep "^Priority" $debcontrol)" && FLAG=true 122 | fi 123 | 124 | 125 | # checking debian/rules file 126 | 127 | inform "checking debian/rules file..." 128 | 129 | if ! grep "debian/python-$packagename" $debrules &> /dev/null; then 130 | warning "$(grep "debian/python-" $debrules)" && FLAG=true 131 | fi 132 | 133 | if ! grep "debian/python3-$packagename" $debrules &> /dev/null; then 134 | warning "$(grep "debian/python3-" $debrules)" && FLAG=true 135 | fi 136 | 137 | # checking debian/README file 138 | 139 | inform "checking debian/readme file..." 140 | 141 | if ! grep -e "$libname" -e "$reponame" $debreadme &> /dev/null; then 142 | warning "README does not seem to mention product, repo or lib!" && FLAG=true 143 | fi 144 | 145 | # summary of checks pre build 146 | 147 | if $FLAG; then 148 | warning "Check all of the above and correct!" && exit 1 149 | else 150 | inform "we're good to go... bulding!" 151 | fi 152 | 153 | # building deb and final checks 154 | 155 | ./makedeb.sh 156 | 157 | inform "running lintian..." 158 | lintian -v $(find -name "python*$version*.deb") 159 | lintian -v $(find -name "python3*$version*.deb") 160 | 161 | inform "checking signatures..." 162 | gpg --verify $(find -name "*$version*changes") 163 | gpg --verify $(find -name "*$version*dsc") 164 | 165 | exit 0 166 | -------------------------------------------------------------------------------- /packaging/makedeb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gettools="yes" # if set to yes downloads the tools required 4 | setup="yes" # if set to yes populates library folder 5 | buildeb="yes" # if set to yes builds the deb files 6 | cleanup="yes" # if set to yes cleans up build files 7 | pkgfiles=( "build" "changes" "deb" "dsc" "tar.xz" ) 8 | 9 | if [ $gettools == "yes" ]; then 10 | sudo apt-get update && sudo apt-get install build-essential debhelper devscripts dh-make dh-python dput gnupg 11 | sudo apt-get install python-all python-setuptools python3-all python3-setuptools 12 | sudo apt-get install python-mock python-sphinx python-sphinx-rtd-theme 13 | sudo pip install Sphinx --upgrade && sudo pip install sphinx_rtd_theme --upgrade 14 | fi 15 | 16 | if [ $setup == "yes" ]; then 17 | rm -R ../library/build ../library/debian &> /dev/null 18 | cp -R ./debian ../library/ && cp -R ../sphinx ../library/doc 19 | fi 20 | 21 | cd ../library 22 | 23 | if [ $buildeb == "yes" ]; then 24 | debuild -aarmhf 25 | for file in ${pkgfiles[@]}; do 26 | rm ../packaging/*.$file &> /dev/null 27 | mv ../*.$file ../packaging 28 | done 29 | rm -R ../documentation/html &> /dev/null 30 | cp -R ./build/sphinx/html ../documentation 31 | fi 32 | 33 | if [ $cleanup == "yes" ]; then 34 | debuild clean 35 | rm -R ./build ./debian ./doc &> /dev/null 36 | fi 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /packaging/makedoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gettools="no" # if set to yes downloads the tools required 4 | setup="yes" # if set to yes populates library folder 5 | buildoc="yes" # if set to yes builds the deb files 6 | cleanup="yes" # if set to yes cleans up build files 7 | pkgfiles=( "build" "changes" "deb" "dsc" "tar.xz" ) 8 | 9 | if [ $gettools == "yes" ]; then 10 | sudo apt-get update && sudo apt-get install build-essential debhelper devscripts dh-make dh-python 11 | sudo apt-get install python-all python-setuptools python3-all python3-setuptools 12 | sudo apt-get install python-mock python-sphinx python-sphinx-rtd-theme 13 | sudo pip install Sphinx --upgrade && sudo pip install sphinx_rtd_theme --upgrade 14 | fi 15 | 16 | if [ $setup == "yes" ]; then 17 | rm -R ../library/build ../library/debian &> /dev/null 18 | cp -R ./debian ../library/ && cp -R ../sphinx ../library/doc 19 | fi 20 | 21 | cd ../library 22 | 23 | if [ $buildoc == "yes" ]; then 24 | debuild 25 | for file in ${pkgfiles[@]}; do 26 | rm ../*.$file &> /dev/null 27 | done 28 | rm -R ../documentation/html &> /dev/null 29 | cp -R ./build/sphinx/html ../documentation 30 | fi 31 | 32 | if [ $cleanup == "yes" ]; then 33 | debuild clean 34 | rm -R ./build ./debian ./doc &> /dev/null 35 | fi 36 | 37 | exit 0 38 | -------------------------------------------------------------------------------- /packaging/makelog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # script control variables 4 | 5 | libname="" # leave this blank for auto-detection 6 | sibname=() # name of sibling in packages list 7 | versionwarn="yes" # set to anything but 'yes' to turn off warning 8 | 9 | debdir="$(pwd)" 10 | rootdir="$(dirname $debdir)" 11 | libdir="$rootdir/library" 12 | 13 | mainlog="CHANGELOG" 14 | debianlog="debian/changelog" 15 | pypilog="$libdir/CHANGELOG.txt" 16 | 17 | # function define 18 | 19 | success() { 20 | echo "$(tput setaf 2)$1$(tput sgr0)" 21 | } 22 | 23 | inform() { 24 | echo "$(tput setaf 6)$1$(tput sgr0)" 25 | } 26 | 27 | warning() { 28 | echo "$(tput setaf 1)$1$(tput sgr0)" 29 | } 30 | 31 | newline() { 32 | echo "" 33 | } 34 | 35 | # generate debian changelog 36 | 37 | cat $mainlog > $debianlog 38 | inform "seeded debian changelog" 39 | 40 | # generate pypi changelog 41 | 42 | sed -e "/--/d" -e "s/ \*/\*/" \ 43 | -e "s/.*\([0-9].[0-9].[0-9]\).*/\1/" \ 44 | -e '/[0-9].[0-9].[0-9]/ a\ 45 | -----' $mainlog | cat -s > $pypilog 46 | 47 | version=$(head -n 1 $pypilog) 48 | inform "pypi changelog generated" 49 | 50 | # touch up version in setup.py file 51 | 52 | if [ -n $(grep version "$libdir/setup.py" &> /dev/null) ]; then 53 | inform "touched up version in setup.py" 54 | sed -i "s/'[0-9].[0-9].[0-9]'/'$version'/" "$libdir/setup.py" 55 | else 56 | warning "couldn't touch up version in setup, no match found" 57 | fi 58 | 59 | # touch up version in lib or package siblings 60 | 61 | if [ -z "$libname" ]; then 62 | cd "$libdir" 63 | libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev) 64 | libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir" 65 | sibname+=( "$libname" ) 66 | elif [ "$libname" != "package" ]; then 67 | sibname+=( "$libname" ) 68 | fi 69 | 70 | for sibling in ${sibname[@]}; do 71 | if grep -e "__version__" "$libdir/$sibling.py" &> /dev/null; then 72 | sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling.py" 73 | inform "touched up version in $sibling.py" 74 | elif grep -e "__version__" "$libdir/$sibling/__init__.py" &> /dev/null; then 75 | sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling/__init__.py" 76 | inform "touched up version in $sibling/__init__.py" 77 | elif [ "$versionwarn" == "yes" ]; then 78 | warning "couldn't touch up __version__ in $sibling, no match found" 79 | fi 80 | done 81 | 82 | exit 0 83 | -------------------------------------------------------------------------------- /sphinx/_static/custom.css: -------------------------------------------------------------------------------- 1 | .rst-content a, .rst-content a:focus { 2 | color:#13c0d7; 3 | } 4 | .rst-content a:visited, .rst-content a:active { 5 | color:#87319a; 6 | } 7 | .rst-content .highlighted { 8 | background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAJElEQVQIW2P8//9/PSMjYyMDEmAEsdElwILoEnBBZAkUQZgEABMWE4Kzp1KUAAAAAElFTkSuQmCC),rgba(246,167,4,0.2); 9 | } 10 | .wy-side-nav-search { 11 | background:#333333; 12 | } 13 | .wy-nav-side { 14 | background:#444444; 15 | } 16 | .rst-content dl:not(.docutils) dt { 17 | background:#e7fafd; 18 | border-top:solid 3px #13c0d7; 19 | color:rgba(0,0,0,0.5); 20 | } 21 | .rst-content .viewcode-link, .rst-content .viewcode-back { 22 | color:#00b09b; 23 | } 24 | code.literal { 25 | color:#e63c2e; 26 | } 27 | .rst-content #module-buttonshim { 28 | margin-bottom:24px; 29 | } 30 | .rst-content #module-buttonshim dl:not(.docutils) dt { 31 | border:none; 32 | background:#f0f0f0; 33 | } 34 | .rst-content #module-buttonshim dl:not(.docutils) dd { 35 | display:none; 36 | } 37 | .rst-content #module-buttonshim dl:not(.docutils) { 38 | margin-bottom:0; 39 | } -------------------------------------------------------------------------------- /sphinx/_templates/breadcrumbs.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pimoroni/button-shim/fce7b220e3a09fa89e8389a94d81e1bc6974d94e/sphinx/_templates/breadcrumbs.html -------------------------------------------------------------------------------- /sphinx/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block extrahead %} 3 | 4 | {% endblock %} -------------------------------------------------------------------------------- /sphinx/conf.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | import sys 4 | import site 5 | 6 | import mock 7 | 8 | 9 | PACKAGE_NAME = u"Button SHIM" 10 | PACKAGE_HANDLE = "ButtonSHIM" 11 | PACKAGE_MODULE = "buttonshim" 12 | 13 | # Prompte /usr/local/lib to the front of sys.path 14 | #sys.path.insert(0,site.getsitepackages()[0]) 15 | 16 | import sphinx_rtd_theme 17 | 18 | sys.modules['RPi'] = mock.Mock() 19 | sys.modules['RPi.GPIO'] = mock.Mock() 20 | 21 | sys.modules['smbus'] = mock.Mock() 22 | 23 | class _SMBus: 24 | def __init__(self, bus_id): 25 | pass 26 | 27 | def write_i2c_block_data(self, addr, reg, data): 28 | pass 29 | 30 | def write_word_data(self, addr, reg, data): 31 | pass 32 | 33 | def write_byte_data(self, addr, reg, data): 34 | pass 35 | 36 | def read_byte_data(self, addr, reg): 37 | return 0 38 | 39 | def read_word_data(self, addr, reg): 40 | return 0 41 | 42 | sys.modules['smbus'].SMBus = _SMBus 43 | 44 | sys.path.insert(0, '../library/') 45 | 46 | import buttonshim 47 | 48 | 49 | from sphinx.ext import autodoc 50 | 51 | 52 | class OutlineMethodDocumenter(autodoc.MethodDocumenter): 53 | objtype = 'method' 54 | 55 | def add_content(self, more_content, no_docstring=False): 56 | return 57 | 58 | class OutlineFunctionDocumenter(autodoc.FunctionDocumenter): 59 | objtype = 'function' 60 | 61 | def add_content(self, more_content, no_docstring=False): 62 | return 63 | 64 | class ModuleOutlineDocumenter(autodoc.ModuleDocumenter): 65 | objtype = 'moduleoutline' 66 | 67 | def __init__(self, directive, name, indent=u''): 68 | # Monkey path the Method and Function documenters 69 | sphinx_app.add_autodocumenter(OutlineMethodDocumenter) 70 | sphinx_app.add_autodocumenter(OutlineFunctionDocumenter) 71 | autodoc.ModuleDocumenter.__init__(self, directive, name, indent) 72 | 73 | def __del__(self): 74 | # Return the Method and Function documenters to normal 75 | sphinx_app.add_autodocumenter(autodoc.MethodDocumenter) 76 | sphinx_app.add_autodocumenter(autodoc.FunctionDocumenter) 77 | 78 | 79 | def setup(app): 80 | global sphinx_app 81 | sphinx_app = app 82 | app.add_autodocumenter(ModuleOutlineDocumenter) 83 | 84 | ModuleOutlineDocumenter.objtype = 'module' 85 | 86 | # -- General configuration ------------------------------------------------ 87 | 88 | # If your documentation needs a minimal Sphinx version, state it here. 89 | # 90 | # needs_sphinx = '1.0' 91 | 92 | # Add any Sphinx extension module names here, as strings. They can be 93 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 94 | # ones. 95 | extensions = [ 96 | 'sphinx.ext.autodoc', 97 | 'sphinx.ext.autosummary', 98 | 'sphinx.ext.viewcode', 99 | ] 100 | 101 | # Add any paths that contain templates here, relative to this directory. 102 | templates_path = ['_templates'] 103 | 104 | # The suffix(es) of source filenames. 105 | # You can specify multiple suffix as a list of string: 106 | # 107 | # source_suffix = ['.rst', '.md'] 108 | source_suffix = '.rst' 109 | 110 | # The encoding of source files. 111 | # 112 | # source_encoding = 'utf-8-sig' 113 | 114 | # The master toctree document. 115 | master_doc = 'index' 116 | 117 | # General information about the project. 118 | project = PACKAGE_NAME 119 | copyright = u'2017, Pimoroni Ltd' 120 | author = u'Phil Howard' 121 | 122 | # The version info for the project you're documenting, acts as replacement for 123 | # |version| and |release|, also used in various other places throughout the 124 | # built documents. 125 | # 126 | # The short X.Y version. 127 | version = u'{}'.format(buttonshim.__version__) 128 | # The full version, including alpha/beta/rc tags. 129 | release = u'{}'.format(buttonshim.__version__) 130 | 131 | # The language for content autogenerated by Sphinx. Refer to documentation 132 | # for a list of supported languages. 133 | # 134 | # This is also used if you do content translation via gettext catalogs. 135 | # Usually you set "language" from the command line for these cases. 136 | language = None 137 | 138 | # There are two options for replacing |today|: either, you set today to some 139 | # non-false value, then it is used: 140 | # 141 | # today = '' 142 | # 143 | # Else, today_fmt is used as the format for a strftime call. 144 | # 145 | # today_fmt = '%B %d, %Y' 146 | 147 | # List of patterns, relative to source directory, that match files and 148 | # directories to ignore when looking for source files. 149 | # This patterns also effect to html_static_path and html_extra_path 150 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 151 | 152 | # The reST default role (used for this markup: `text`) to use for all 153 | # documents. 154 | # 155 | # default_role = None 156 | 157 | # If true, '()' will be appended to :func: etc. cross-reference text. 158 | # 159 | # add_function_parentheses = True 160 | 161 | # If true, the current module name will be prepended to all description 162 | # unit titles (such as .. function::). 163 | # 164 | # add_module_names = True 165 | 166 | # If true, sectionauthor and moduleauthor directives will be shown in the 167 | # output. They are ignored by default. 168 | # 169 | # show_authors = False 170 | 171 | # The name of the Pygments (syntax highlighting) style to use. 172 | pygments_style = 'sphinx' 173 | 174 | # A list of ignored prefixes for module index sorting. 175 | # modindex_common_prefix = [] 176 | 177 | # If true, keep warnings as "system message" paragraphs in the built documents. 178 | # keep_warnings = False 179 | 180 | # If true, `todo` and `todoList` produce output, else they produce nothing. 181 | todo_include_todos = False 182 | 183 | 184 | # -- Options for HTML output ---------------------------------------------- 185 | 186 | # The theme to use for HTML and HTML Help pages. See the documentation for 187 | # a list of builtin themes. 188 | # 189 | html_theme = 'sphinx_rtd_theme' 190 | #html_theme = 'alabaster' 191 | 192 | # Theme options are theme-specific and customize the look and feel of a theme 193 | # further. For a list of options available for each theme, see the 194 | # documentation. 195 | # 196 | html_theme_options = { 197 | 'collapse_navigation': False, 198 | 'display_version': True 199 | } 200 | 201 | # Add any paths that contain custom themes here, relative to this directory. 202 | html_theme_path = [ 203 | '_themes', 204 | sphinx_rtd_theme.get_html_theme_path() 205 | ] 206 | 207 | # The name for this set of Sphinx documents. 208 | # " v documentation" by default. 209 | # 210 | # html_title = PACKAGE_NAME + u' v0.1.2' 211 | 212 | # A shorter title for the navigation bar. Default is the same as html_title. 213 | # 214 | # html_short_title = None 215 | 216 | # The name of an image file (relative to this directory) to place at the top 217 | # of the sidebar. 218 | # 219 | html_logo = 'shop-logo.png' 220 | 221 | # The name of an image file (relative to this directory) to use as a favicon of 222 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 223 | # pixels large. 224 | # 225 | html_favicon = 'favicon.png' 226 | 227 | # Add any paths that contain custom static files (such as style sheets) here, 228 | # relative to this directory. They are copied after the builtin static files, 229 | # so a file named "default.css" will overwrite the builtin "default.css". 230 | html_static_path = ['_static'] 231 | 232 | # Add any extra paths that contain custom files (such as robots.txt or 233 | # .htaccess) here, relative to this directory. These files are copied 234 | # directly to the root of the documentation. 235 | # 236 | # html_extra_path = [] 237 | 238 | # If not None, a 'Last updated on:' timestamp is inserted at every page 239 | # bottom, using the given strftime format. 240 | # The empty string is equivalent to '%b %d, %Y'. 241 | # 242 | # html_last_updated_fmt = None 243 | 244 | # If true, SmartyPants will be used to convert quotes and dashes to 245 | # typographically correct entities. 246 | # 247 | # html_use_smartypants = True 248 | 249 | # Custom sidebar templates, maps document names to template names. 250 | # 251 | # html_sidebars = {} 252 | 253 | # Additional templates that should be rendered to pages, maps page names to 254 | # template names. 255 | # 256 | # html_additional_pages = {} 257 | 258 | # If false, no module index is generated. 259 | # 260 | # html_domain_indices = True 261 | 262 | # If false, no index is generated. 263 | # 264 | html_use_index = False 265 | 266 | # If true, the index is split into individual pages for each letter. 267 | # 268 | # html_split_index = False 269 | 270 | # If true, links to the reST sources are added to the pages. 271 | # 272 | html_show_sourcelink = False 273 | 274 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 275 | # 276 | html_show_sphinx = False 277 | 278 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 279 | # 280 | # html_show_copyright = True 281 | 282 | # If true, an OpenSearch description file will be output, and all pages will 283 | # contain a tag referring to it. The value of this option must be the 284 | # base URL from which the finished HTML is served. 285 | # 286 | # html_use_opensearch = '' 287 | 288 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 289 | # html_file_suffix = None 290 | 291 | # Language to be used for generating the HTML full-text search index. 292 | # Sphinx supports the following languages: 293 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 294 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' 295 | # 296 | # html_search_language = 'en' 297 | 298 | # A dictionary with options for the search language support, empty by default. 299 | # 'ja' uses this config value. 300 | # 'zh' user can custom change `jieba` dictionary path. 301 | # 302 | # html_search_options = {'type': 'default'} 303 | 304 | # The name of a javascript file (relative to the configuration directory) that 305 | # implements a search results scorer. If empty, the default will be used. 306 | # 307 | # html_search_scorer = 'scorer.js' 308 | 309 | # Output file base name for HTML help builder. 310 | htmlhelp_basename = PACKAGE_HANDLE + 'doc' 311 | 312 | # -- Options for LaTeX output --------------------------------------------- 313 | 314 | latex_elements = { 315 | # The paper size ('letterpaper' or 'a4paper'). 316 | # 317 | # 'papersize': 'letterpaper', 318 | 319 | # The font size ('10pt', '11pt' or '12pt'). 320 | # 321 | # 'pointsize': '10pt', 322 | 323 | # Additional stuff for the LaTeX preamble. 324 | # 325 | # 'preamble': '', 326 | 327 | # Latex figure (float) alignment 328 | # 329 | # 'figure_align': 'htbp', 330 | } 331 | 332 | # Grouping the document tree into LaTeX files. List of tuples 333 | # (source start file, target name, title, 334 | # author, documentclass [howto, manual, or own class]). 335 | latex_documents = [ 336 | (master_doc, PACKAGE_HANDLE + '.tex', PACKAGE_NAME + u' Documentation', 337 | u'Phil Howard', 'manual'), 338 | ] 339 | 340 | # The name of an image file (relative to this directory) to place at the top of 341 | # the title page. 342 | # 343 | # latex_logo = None 344 | 345 | # For "manual" documents, if this is true, then toplevel headings are parts, 346 | # not chapters. 347 | # 348 | # latex_use_parts = False 349 | 350 | # If true, show page references after internal links. 351 | # 352 | # latex_show_pagerefs = False 353 | 354 | # If true, show URL addresses after external links. 355 | # 356 | # latex_show_urls = False 357 | 358 | # Documents to append as an appendix to all manuals. 359 | # 360 | # latex_appendices = [] 361 | 362 | # It false, will not define \strong, \code, itleref, \crossref ... but only 363 | # \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added 364 | # packages. 365 | # 366 | # latex_keep_old_macro_names = True 367 | 368 | # If false, no module index is generated. 369 | # 370 | # latex_domain_indices = True 371 | 372 | 373 | # -- Options for manual page output --------------------------------------- 374 | 375 | # One entry per manual page. List of tuples 376 | # (source start file, name, description, authors, manual section). 377 | man_pages = [ 378 | (master_doc, PACKAGE_MODULE, PACKAGE_NAME + u' Documentation', 379 | [author], 1) 380 | ] 381 | 382 | # If true, show URL addresses after external links. 383 | # 384 | # man_show_urls = False 385 | 386 | 387 | # -- Options for Texinfo output ------------------------------------------- 388 | 389 | # Grouping the document tree into Texinfo files. List of tuples 390 | # (source start file, target name, title, author, 391 | # dir menu entry, description, category) 392 | texinfo_documents = [ 393 | (master_doc, PACKAGE_HANDLE, PACKAGE_NAME + u' Documentation', 394 | author, PACKAGE_HANDLE, 'One line description of project.', 395 | 'Miscellaneous'), 396 | ] 397 | 398 | # Documents to append as an appendix to all manuals. 399 | # 400 | # texinfo_appendices = [] 401 | 402 | # If false, no module index is generated. 403 | # 404 | # texinfo_domain_indices = True 405 | 406 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 407 | # 408 | # texinfo_show_urls = 'footnote' 409 | 410 | # If true, do not generate a @detailmenu in the "Top" node's menu. 411 | # 412 | # texinfo_no_detailmenu = False 413 | -------------------------------------------------------------------------------- /sphinx/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pimoroni/button-shim/fce7b220e3a09fa89e8389a94d81e1bc6974d94e/sphinx/favicon.png -------------------------------------------------------------------------------- /sphinx/index.rst: -------------------------------------------------------------------------------- 1 | .. role:: python(code) 2 | :language: python 3 | 4 | .. toctree:: 5 | :titlesonly: 6 | :maxdepth: 0 7 | 8 | Welcome 9 | ------- 10 | 11 | This documentation will guide you through the methods available in the Button SHIM python library. 12 | 13 | Button SHIM is a tiny Raspberry Pi add-on with 5 tactile buttons and one teeny RGB LED. 14 | 15 | * More information - https://shop.pimoroni.com/products/button-shim 16 | * Get the code - https://github.com/pimoroni/button-shim 17 | * Get help - http://forums.pimoroni.com/c/support 18 | 19 | At A Glance 20 | ----------- 21 | 22 | .. automoduleoutline:: buttonshim 23 | :members: 24 | 25 | Set The Pixel 26 | ------------- 27 | 28 | .. automodule:: buttonshim 29 | :noindex: 30 | :members: set_pixel 31 | 32 | Handle A Button Press 33 | --------------------- 34 | 35 | .. automodule:: buttonshim 36 | :noindex: 37 | :members: on_press 38 | 39 | Handle A Button Release 40 | ----------------------- 41 | 42 | .. automodule:: buttonshim 43 | :noindex: 44 | :members: on_release 45 | 46 | Handle A Button Hold 47 | -------------------- 48 | 49 | .. automodule:: buttonshim 50 | :noindex: 51 | :members: on_hold 52 | 53 | Get The Name Of A Button 54 | ------------------------ 55 | 56 | .. automodule:: buttonshim 57 | :noindex: 58 | :members: NAMES 59 | 60 | -------------------------------------------------------------------------------- /sphinx/shop-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pimoroni/button-shim/fce7b220e3a09fa89e8389a94d81e1bc6974d94e/sphinx/shop-logo.png --------------------------------------------------------------------------------