{"id":17384253,"url":"https://github.com/bkahlert/pihero","last_synced_at":"2025-08-03T03:30:56.087Z","repository":{"id":186839045,"uuid":"675143704","full_name":"bkahlert/pihero","owner":"bkahlert","description":"Ansible-based tool to make your Raspberry Pi discoverable, accessible, and fun to use","archived":false,"fork":false,"pushed_at":"2024-03-17T17:10:42.000Z","size":6614,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-17T12:27:06.835Z","etag":null,"topics":["ansible","ethernet","gadget","network","raspberry-pi","raspberrypi","rpi","usb"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bkahlert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"custom":"paypal.me/bkahlert"}},"created_at":"2023-08-05T23:44:40.000Z","updated_at":"2024-04-10T21:10:19.000Z","dependencies_parsed_at":"2024-03-08T01:45:32.037Z","dependency_job_id":"3ff2063e-c908-4fca-a20f-680cb8d1fb7f","html_url":"https://github.com/bkahlert/pihero","commit_stats":null,"previous_names":["bkahlert/pihero"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkahlert%2Fpihero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkahlert%2Fpihero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkahlert%2Fpihero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bkahlert%2Fpihero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bkahlert","download_url":"https://codeload.github.com/bkahlert/pihero/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228518273,"owners_count":17932431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ethernet","gadget","network","raspberry-pi","raspberrypi","rpi","usb"],"created_at":"2024-10-16T07:44:58.009Z","updated_at":"2024-12-06T19:40:40.981Z","avatar_url":"https://github.com/bkahlert.png","language":"Shell","funding_links":["paypal.me/bkahlert","https://www.buymeacoffee.com/bkahlert","https://www.paypal.me/bkahlert"],"categories":[],"sub_categories":[],"readme":"# Pi Hero [![License](https://img.shields.io/github/license/bkahlert/pihero?color=29ABE2\u0026label=License\u0026logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1OTAgNTkwIiAgeG1sbnM6dj0iaHR0cHM6Ly92ZWN0YS5pby9uYW5vIj48cGF0aCBkPSJNMzI4LjcgMzk1LjhjNDAuMy0xNSA2MS40LTQzLjggNjEuNC05My40UzM0OC4zIDIwOSAyOTYgMjA4LjljLTU1LjEtLjEtOTYuOCA0My42LTk2LjEgOTMuNXMyNC40IDgzIDYyLjQgOTQuOUwxOTUgNTYzQzEwNC44IDUzOS43IDEzLjIgNDMzLjMgMTMuMiAzMDIuNCAxMy4yIDE0Ny4zIDEzNy44IDIxLjUgMjk0IDIxLjVzMjgyLjggMTI1LjcgMjgyLjggMjgwLjhjMCAxMzMtOTAuOCAyMzcuOS0xODIuOSAyNjEuMWwtNjUuMi0xNjcuNnoiIGZpbGw9IiNmZmYiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxOS4yMTIiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4%3D)](https://github.com/bkahlert/pihero/blob/master/LICENSE) [![Buy Me A Unicorn](https://img.shields.io/static/v1?label=\u0026message=Buy%20Me%20A%20Unicorn\u0026color=c21f73\u0026logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3MiA3MiI%2BPHBhdGggZmlsbD0iI0ZGRiIgZD0iTTIzLjc1NCAxMi4zNjJsMS42NjcgNy4xNjctNS4zMzMgNS4zMzMtOC4zMzQgMTQuMzMzIDEgNC42NjcgMi4xNjcgMS4zMzMgNC0uMTY3IDMuNS0zLjMzMyA2LjgzMy0xLjgzM3MxLjMzNCAxLjUgMi4xNjcgMyAzLjY2NyA0LjE2NyAzLjY2NyA0LjE2N2wuNSA2LTEuODMzIDYuMTY2LTIgMi44MzNzMjIgOS41IDMzLjE2Ni03bC0uNS02LTEuODMzLTUtMy4zMzMtNS4xNjYtMS0xLjUtLjE2Ny01LjE2Ny0yLjgzMy01LjMzMy01LTMtMi42NjctNC41LTUuMTY3LTQuMTY3LTYuNS0xLjUtNS42NjYgMS00LjE2Ny0yLjE2Ny0yLjMzNC0uMTY2eiIvPjxwYXRoIGZpbGw9IiNFQTVBNDciIGQ9Ik01MC42NzEgMjMuMTU1bDUuMjA4IDQuMDk1czUuNTY0IDguMjE4LS4zMjUgMTcuODJjLTcuMDUgMTEuNDkyIDAgMCAwIDAtMS42MTkgMy40NzUtMi4zMTUgNi43NDItMS43MzkgOS43MjJsLTUuMzEtNC40MTdWMzQuMjkybDIuMTY2LTExLjEzN3pNMjUuODk4IDE5LjI3MWwtMTUuMTEzLTcuMjUgNS4xNjYgNi4xMTkgNS4yMjQgNS44NTUgNC43MjMtNC43MjQiLz48cGF0aCBmaWxsPSIjOTJEM0Y1IiBkPSJNMjkuNzM3IDEzLjYzMWwxMC43NjcuMTM2czkuMjM4IDQuMDY2IDEwLjUzNiAxMS44MTZsLjY4NyA4Ljk1N2MtMi42MzMgNi41MzktMy4wNTYgMTQuMTI3IDIuMDg5IDIwLjgzNCAwIDAtNy4xNDUgMS4zMjEtOS44OTUtNy4xMUw0Mi4zMzggNDMuNWwuMzI1LTYuMDM0IDEuNDE3LTUuNjQzLS4yODMtNC44OTMtMi4yNzYtNC4zMTItMy41MzItMi44NDEtNS43OTItMi4wOC0yLjQ2LTQuMDY2Ii8%2BPHBhdGggZmlsbD0iIzYxQjJFNCIgZD0iTTU4LjQ1NSAzNi43NXM1LjUyIDYuNDA3IDYuOTk4IDE1LjEyYTguMDIgOC4wMiAwIDAxLS4xMzggMy4yNThjLS40MzEgMS43NTItLjgxNyA0Ljk5OC4xNDYgNy4zODMuNDY5IDEuMTYxLS41NjIgMi4zNjUtMS43ODkgMi4xMTEtMy43MS0uNzY4LTkuMjQzLTMuNjQ3LTEwLjI1Ni04LjA4N2ExLjgyNiAxLjgyNiAwIDAxLS4wNDItLjMyMWwtLjI2Ni01Ljc0NmMtLjAxMy0uMjg2LjA1Mi0uNTcuMTg3LS44MjFsMy42OTItNi44MzZjLjA2Ny0uMTIzLjExNy0uMjU1LjE0OS0uMzkybDEuMzE5LTUuNjY5Ii8%2BPGc%2BPHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIyIiBkPSJNNTguNDU1IDM3Ljc4M0M2MC4yMjMgNDAuMTQ0IDY1IDQ0LjQ2NSA2NC41IDU0LjAyTTMyLjUgNDEuODg1czguNDc4IDYuNzgzIDAgMTguNzY1TTI0LjgwOSAxOS4xMzRMMTAuMjUgMTEuNzVsMTAuOTI1IDEyLjI0NSIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTM1LjE5NiAzMC44N2MuNTUgOC4zNTUtOS4zMjIgOS43MDMtMTEuOTU0IDEwLjMzNC0uMzMyLjA4LS42MzIuMjUtLjg3My40OTJsLTIuMjIzIDIuMjIzYy0uMzUuMzUtLjgyNC41NDYtMS4zMTguNTQ2aC0zLjUxMmEyLjc5NSAyLjc5NSAwIDAxLTIuNjUxLTEuOTExbC0uNTMxLTEuNTkzYTIuNzk1IDIuNzk1IDAgMDEuMjU1LTIuMzIybDguNzg2LTE0LjY0NCA0LjcyNC00LjcyNC0yLjExNi02LjkwNXM3LjgwMy0uNjk5IDguNDE0IDUuMzNjMCAwIDE2LjkyOCAyLjQ0MiAxMC41NTMgMTkuMzg0IDAgMC0xLjYyNSA1Ljk0OSAyLjM3NSAxMS4xODRNMzAuOTE3IDE0LjAyUzUzLjE2IDEwIDUwLjg3NSAzMy45OCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iMiIgZD0iTTQ5LjkxOSAyMy4xNTVzMTQuNzY2IDYuNTg3IDUuNDU2IDIyLjIyYzAgMC01LjM3NSA2LjU2My42MjUgMTMuNjA0Ii8%2BPGNpcmNsZSBjeD0iMjQuNDE3IiBjeT0iMjguOTMiIHI9IjIiLz48L2c%2BPC9zdmc%2B)](https://www.buymeacoffee.com/bkahlert)\n\n![Pi Hero Banner](assets%2Fpihero-banner.svg)\n\n## About\n\n**Pi Hero** is an Ansible-based tool to make your [Raspberry Pi](https://www.raspberrypi.com/)\ndiscoverable, accessible, and fun to use.\n\nPi Hero makes your Raspberry Pi:\n\n- show a splash screen during boot and shutdown,\n- show up in your network with a nice icon,\n- share device information,\n- create an Ethernet over USB connection,\n- configure Windows-compatible Samba shares,\n- accept serial connection, and\n- allow for custom features like behaving like a keyboard, mouse, mass storage, etc.\n- create a Bluetooth PAN\n\nSupported are even old models like the [Raspberry Pi Zero](https://www.raspberrypi.com/products/raspberry-pi-zero/) with no network accessibility at all.\n\n## Features\n\n### Easy configuration\n\nA [sample inventory](inventory/sample/hosts.yml) for sample devices, namely `foo.local` and `bar.local` is provided to get you started:\n\n```yaml\n# Device \"foo\" with the following features:\n# - Bluetooth PAN with custom CIDR and one (pre-)trusted device\n# - Ethernet over USB\nfoo.local:\n    bt_pan:\n        cidr: 10.11.10.10/29\n        devices: { mac: 00:11:22:33:44:55, pin: '*', trusted: true }\n    usb_gadget:\n        ethernet:\n\n# Device \"bar\" with custom model and the following features:\n# - Ethernet over USB with custom CIDR\n# - USB Serial Port\n# - custom USB Mass Storage\nbar.local:\n    device_info: { model: MacPro7,1@ECOLOR=226,226,224 }\n    usb_gadget:\n        ethernet: { cidr: 10.10.20.20/29 }\n        serial:\n        mass_storage: # ...\n```\n\n### Discoverable\n\nAvahi is installed to make your Raspberry Pi discoverable in your network.\nBy default, your Raspberry Pi shows up as a 4th-generation AirPort device.\nThe samba shares, SSH, and SFTP services are advertised as well.\n\n| [![network browser](docs%2Fnetwork-browser.png) foo.local and bar.local in network browser](./docs/network-browser.png) | [![network info foo](docs%2Fnetwork-info-foo.png) foo.local info](./docs/network-info-foo.png) | [![network info bar](docs%2Fnetwork-info-bar.png) bar.local info](./docs/network-info-bar.png) |\n|-------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------|\n\n### Accessible\n\n#### File sharing\n\nSamba shares are configured for home directories and the root directory `/`.\n\u003e ℹ️ Don't forget to set a Samba password using `sudo smbpasswd -a $USER`\n\u003e [![samba password](docs%2Fsamba-password.png)](./docs/samba-password.png)\n\n| [![samba login](docs%2Fsamba-login.png) samba login](./docs/samba-login.png) | [![samba shares](docs%2Fsamba-shares.png) samba shares](./docs/samba-shares.png) | [![samba home share](docs%2Fsamba-home-share.png) samba home share](./docs/samba-home-share.png) | [![samba rootfs share](docs%2Fsamba-rootfs-share.png) samba rootfs share](./docs/samba-rootfs-share.png) |\n|------------------------------------------------------------------------------|----------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|\n\n#### Bluetooth PAN\n\nIf your device has Bluetooth, a Personal Area Network `PAN`—more specifically a Network Access Point `NAP`—can be created.\nIt lets your configured devices connect to your Raspberry Pi via Bluetooth.\n\n| [![discoverable Raspberry Pi](docs%2Fbt-pan-discoverable.png) discoverable Raspberry Pi\u003cbr/\u003e](./docs/bt-pan-discoverable.png) | [![connected with Mac via Bluetooth PAN](docs%2Fbt-pan-connected.png) connected with Mac via Bluetooth PAN\u003cbr/\u003e](./docs/bt-pan-connected.png) | [![ping with iPhone via Bluetooth PAN](docs%2Fbt-pan-ping.png) ping with iPhone via Bluetooth](./docs/bt-pan-ping.png) | [![samba share via Bluetooth PAN](docs%2Fbt-pan-share.png) samba share accessed with iPhone via Bluetooth](./docs/bt-pan-share.png) |\n|-------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|\n\nDevices are identified by their MAC address. To find out your device's MAC address:\n\n- On macOS, run `system_profiler SPBluetoothDataType | grep \"Address:\" | head -n 1`\n- On an iPhone, go to `Settings` \u003e `General` \u003e `About` \u003e `Bluetooth`\n- On Windows, run `ipconfig /all | findstr \"Bluetooth\"`\n- On Linux, run `bt-adapter -i | grep \"Address:\" | head -n 1`\n\n#### Ethernet over USB\n\nIf your device has no Wi-Fi or Ethernet port, or you use them for a different purpose,\njust connect via USB.\nAn Ethernet over USB network interface is automatically created and configured.\n\n| [![network devices](docs%2Fnetwork-devices.png) USB network devices](./docs/network-devices.png) | [![network device rpi 0](docs%2Fnetwork-device-rpi0.png) bar.local USB network device](./docs/network-device-rpi-0.png) | [![network device rpi 0 details](docs%2Fnetwork-device-rpi0-details.png) bar.local network device details](./docs/network-device-rpi-0-details.png) |\n|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|\n\nBy default, your Raspberry Pi uses the IP address `10.10.10.10`, and\nconfigures your computer via DHCP.\n\nThe most complicated part is to use the right USB port: you'll need to use the so-called USB-OTG port.\nIt's typically the one in the middle.\n\n#### Serial port\n\nAdditionally, a serial port over USB is set up.\n\n| [![serial device](docs%2Fserial-device.png) Serial device on the host](./docs/serial-device.png) | [![serial login](docs%2Fserial-login.png) Login using serial connection](./docs/serial-login.png) | [![serial logged in](docs%2Fserial-logged-in.png) Logged-in using serial connection](./docs/serial-logged-in.png) | [![serial ping to host](docs%2Fserial-ping-to-host.png) Successful ping of host](./docs/serial-ping-to-host.png) |\n|--------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|\n\n- To list all available serial ports, type `ls /dev/tty.usbmodem*`.\n- To connect to the first available serial port, you need a terminal emulator program such as:\n    - `screen $(ls /dev/tty.usbmodem* | head -n 1) 115200` (exit with `Ctrl+A` `K`)\n    - `cu -s 115200 -l $(ls /dev/tty.usbmodem* | head -n 1)` (exit with `~.`)\n    - `minicom -b 115200 -D $(ls /dev/tty.usbmodem* | head -n 1)` (exit with `Meta+Z` `X`)\n\n### Maintainable\n\nThe `pihero` tool provides diagnostics, that help you resolve problems.\n\nSimply type `pihero diag` to get a report on possible configuration problems.\n\n| [![Pi Hero commands](docs%2Fpihero-commands.png) Available Pi Hero commands](./docs/pihero-commands.png) | [![Pi Hero succeeded diagnostics](docs%2Fpihero-diag-succeeded.png) Succeeded diagnostics](./docs/pihero-diag-succeeded.png) | [![Pi Hero failed diagnostics](docs%2Fpihero-diag-failed.png) Failed diagnostics](./docs/pihero-diag-failed.png) |\n|----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|\n\n### Extensible\n\nThe USB-based features are based on the Linux\nkernel's [multifunction composite gadget, or g_multi](https://www.kernel.org/doc/html/latest/usb/gadget_multi.html).\nThe gadget is configured using [a shell script](roles/usb_gadget/templates/usb-gadget.sh.j2) that supports any gadget function,\nyou would like your Raspberry Pi to provide.\n\nThe serial port and USB over Ethernet functions are supported by default.\n\nThe following configuration shows a custom USB mass storage gadget that creates a 1 GB removable hard drive:\n\n```yaml\nusb_gadget:\n    mass_storage: |\n        #!/usr/bin/env bash\n\n        # create disk image\n        if [ ! -f /data/hdd.img ]; then\n          mkdir -p /data\n          fallocate -l 1GB /data/hdd.img\n          mkfs.exfat -v -L 'RaspiDrive' -f /data/hdd.img\n        fi\n\n        # create mass storage gadget, see kernel.org/doc/html/latest/usb/gadget-testing.html#mass-storage-function\n        echo 1 \u003estall\n        echo /data/hdd.img                  \u003e lun.0/file\n        echo 'SanDisk Cruzer Edge     1.20' \u003e lun.0/inquiry_string\n        echo 1                              \u003e lun.0/removable\n```\n\n| [![mass storage drive info](docs%2Fmass_storage-drive-info.png) Drive info](./docs/mass-storage-drive-info.png) | [![mass storage drive details](docs%2Fmass_storage-drive-details.png) Drive details](./docs/mass-storage-drive-details.png) |\n|-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|\n\n- You can add any supported gadget function, e.g. `hid`, or `mass_storage` (see above) to the `usb_gadget` node\n  of your Ansible configuration.\n- The value needs to be a shell script (either inline, or the path to it on your device).\n- The most part is already done for you.\n- All you have to do is to configure the function itself.\n- The necessary `functions/\u003cfunction\u003e.\u003cinstance\u003e` directory is already created and the working directory of your script.\n- If your script does not exit with code `0`, the function will simply not be enabled.\n- Eventually occurred problems are logged, see [Troubleshooting](#troubleshooting).\n\n## Installation\n\n### Preparations\n\n- Install Ansible on your computer.\n- Checkout this repository:\n  ```shell\n  git clone https://github.com/bkahlert/pihero.git\n  cd pihero\n  ```\n\n### Configuration\n\n- Copy the [sample inventory](inventory/sample) to `inventory/berries` and adapt it to your needs:\n  ```shell\n  cp -r inventory/sample inventory/berries\n  ```\n\nBy default, your device is advertised as an AirPort (4th generation) device.\nAfter having tried a dozen configurations, this one turned out to be the best,\nbecause it's recognized by most devices, is of kind `Mac` but looks like a\ntiny network device and not like a classical computer.\n\nIf you'd like to go with a different configuration, these are the ones I'd recommend:\n\n| Model   |                                           `AirPort4`                                            |                                           `AirPort5`                                            |                                        `AirPort6`                                         |                                       `Macmini8,1`                                        |                                       `Macmini9,1`                                        |                                           `MacPro6,1`                                           |                                  `MacPro5,1`                                  |                      `MacPro7,1`\u003cbr/\u003e`@ECOLOR=`\u003cbr/\u003e`225,225,223`                       |                                `MacPro7,1`\u003cbr/\u003e`@ECOLOR=`\u003cbr/\u003e`226,226,224`                                 |                                  `Xserve3,1`                                  |\n|---------|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------:|\n| Kind    |                                               Mac                                               |                                         AirPort Extreme                                         |                                       Time Capsule                                        |                                            Mac                                            |                                            Mac                                            |                                               Mac                                               |                                      Mac                                      |                                           Mac                                           |                                                     Mac                                                     |                                      Mac                                      |\n| Icon    |         ![com.apple.airport-express.png](docs%2Fmodels%2Fcom.apple.airport-express.png)         |         ![com.apple.airport-extreme.png](docs%2Fmodels%2Fcom.apple.airport-extreme.png)         |         ![com.apple.time-capsule.png](docs%2Fmodels%2Fcom.apple.time-capsule.png)         |         ![com.apple.macmini-2018.png](docs%2Fmodels%2Fcom.apple.macmini-2018.png)         |         ![com.apple.macmini-2020.png](docs%2Fmodels%2Fcom.apple.macmini-2020.png)         |         ![com.apple.macpro-cylinder.png](docs%2Fmodels%2Fcom.apple.macpro-cylinder.png)         |         ![com.apple.macpro.png](docs%2Fmodels%2Fcom.apple.macpro.png)         |         ![com.apple.macpro-2019.png](docs%2Fmodels%2Fcom.apple.macpro-2019.png)         |         ![com.apple.macpro-2019-rackmount.png](docs%2Fmodels%2Fcom.apple.macpro-2019-rackmount.png)         |         ![com.apple.xserve.png](docs%2Fmodels%2Fcom.apple.xserve.png)         |\n| Sidebar | ![com.apple.airport-express-sidebar.png](docs%2Fmodels%2Fcom.apple.airport-express-sidebar.png) | ![com.apple.airport-extreme-sidebar.png](docs%2Fmodels%2Fcom.apple.airport-extreme-sidebar.png) | ![com.apple.time-capsule-sidebar.png](docs%2Fmodels%2Fcom.apple.time-capsule-sidebar.png) | ![com.apple.macmini-2018-sidebar.png](docs%2Fmodels%2Fcom.apple.macmini-2018-sidebar.png) | ![com.apple.macmini-2020-sidebar.png](docs%2Fmodels%2Fcom.apple.macmini-2020-sidebar.png) | ![com.apple.macpro-cylinder-sidebar.png](docs%2Fmodels%2Fcom.apple.macpro-cylinder-sidebar.png) | ![com.apple.macpro-sidebar.png](docs%2Fmodels%2Fcom.apple.macpro-sidebar.png) | ![com.apple.macpro-2019-sidebar.png](docs%2Fmodels%2Fcom.apple.macpro-2019-sidebar.png) | ![com.apple.macpro-2019-rackmount-sidebar.png](docs%2Fmodels%2Fcom.apple.macpro-2019-rackmount-sidebar.png) | ![com.apple.xserve-sidebar.png](docs%2Fmodels%2Fcom.apple.xserve-sidebar.png) |\n\n### Raspberry Pi preparation\n\n- Flash the latest Raspberry Pi OS Lite image to your SD card.\n- Boot your Raspberry Pi and connect it to your network.\n\n| Using Wi-Fi                                                                                                           | Using Ethernet                                                       | Using USB                                                  |\n|-----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|------------------------------------------------------------|\n| Configure your Wi-Fi upfront.\u003cbr\u003eThe easiest way to do that is using the Raspberry Pi Imager's customization feature. | Connect your Pi with an Ethernet cable to your DHCP enabled network. | Use a USB to Ethernet adapter and connect to your network. |\n\n- Locate your Raspberry Pi\n    - Ideally you should be able to ping your device using `ping raspberry.local`, or the hostname you configured.\n    - If that doesn't work, you can\n        - use [netmon](https://github.com/bkahlert/netmon),\n        - check your Router's web interface, or\n        - scan your network with `nmap -sn nmap -sn 192.168.0.0/24` *(adapt to your network)*\n    - If you can't, you can use `nmap` to scan your network for devices:\n\n### Ansible\n\n- Start the setup process using:\n  ```shell\n  # Setup only the device foo.local\n  ansible-playbook playbook.yml -l foo.local\n  \n  # Setup only the device foo.local declared in the given inventory, and use the specified IP address to connect\n  ansible-playbook playbook.yml -l foo.local \\\n      -e \"ansible_host=10.10.10.99\" \\\n      -i inventory/other/hosts.yml\n  ```\n    - If you used the provided [sample inventory](inventory/sample/hosts.yml) with two Raspberry Pis,   \n      the output should look like the one in [sample-installation.md](sample-installation.md).\n\n    - Alternatively, you can integrate Pi Hero in your playbook with the following snippet:\n      ```yaml\n      - hosts: \"{{ inventory if inventory is defined else 'all' }}\"\n        gather_facts: false\n        tasks:\n          - name: check if plymouth-themes directory exists\n            ansible.builtin.stat: { path: \"{{ playbook_dir }}/plymouth-themes/\" } # ← used to store custom splash screens\n            register: plymouth_themes_stat\n          - name: set fact for local_plymouth_themes_dir\n            set_fact: { local_plymouth_themes_dir: \"{{ playbook_dir }}/plymouth-themes/\" }\n            when: plymouth_themes_stat.stat.isdir is defined and plymouth_themes_stat.stat.isdir\n            tags: [ never, pihero ]\n    \n      - name: run Pi Hero playbook, if --tags pihero is specified\n        ansible.builtin.import_playbook: ../../pihero/playbook.yml                # ← location of Pi Hero\n        tags: [ never, pihero ]\n      ```\n      To run the Pi Hero playbook, add `--tags pihero` to your `ansible-playbook` command.\n\n- Wait for the playbook to finish and your Raspberry Pi to reboot.\n\n    - If you used a USB to Ethernet adapter, you should remove the adapter and connect to your computer directly.\n    - You can do so when the Raspberry Pi is about\n      to reboot.\n    - If you missed this moment, just unplug the adapter and restart.\n\n**Your Raspberry Pi is now ready to use, and should show up in your network properly.**\n\n| [![device info foo](docs%2Fdevice-info-foo.png) foo.local device information](./docs/device-info-foo.png) | [![device info bar](docs%2Fdevice-info-bar.png) bar.local device information](./docs/device-info-bar.png) |\n|-----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|\n\n## Usage\n\nLog in using `ssh foo.local` and you'll be greeted\nwith a message containing information about the configured features:\n\n```text\nLinux gadget 6.1.21-v8+ #1642 SMP PREEMPT aarch64\n\n─=≡▰▩▩[ 蓬•ｏ•]⊐ Shares\n    smb://foo.local/pi → /home/pi\n    smb://foo.local/rootfs → / (read-only)\n\n─=≡▰▩▩[ 蓬•ｏ•]⊐ USB gadget\n    FEATURES: mass_storage, serial, ethernet\n\n─=≡▰▩▩[ 蓬•ｏ•]⊐ USB ethernet\n    INTERFACE: usb0 — IP 10.10.10.10 / 255.255.255.248 — DHCP: 10.10.10.11 - 10.10.10.14\n    HELP: pihero gadget\n\n─=≡▰▩▩[ 蓬•ｏ•]⊐ Bluetooth PAN\n    INTERFACE: usb0 — IP 10.11.10.10 / 255.255.255.248 — DHCP: 10.11.10.11 - 10.11.10.14\n    HELP: pihero pan\n\nLast login from 10.10.10.12\n```\n\n## Troubleshooting\n\nYou can run a diagnosis script with:\n\n```shell\n# all diagnostics\npihero diag\n\n# or\n\n# only USB gadget diagnostics\npihero gadget diag\n```\n\n[![usb gadget diag](docs%2Fusb-gadget-diag.png)](./docs/usb-gadget-diag.png)\n\nIt produces output like the following with additional hints\non how to proceed\n\n```\nChecking if /boot/config.txt contains dtoverlay=dwc2... ✔︎\nChecking if /boot/cmdline.txt contains modules-load=dwc2... ✔︎\nChecking if /boot/cmdline.txt contains no line breaks... ✔︎\nChecking if libcomposite module is loaded... ✔︎\nChecking if usb-gadget service is active... ✔︎\n# ...\nChecking if usb0 interface config is not malformed... ✔︎\nChecking if usb0 interface config is not malformed... ✔︎\nChecking if usb0 interface exists... ✔︎\nAll checks passed.\n\n  Useful commands:\n  - check usb-gadget service: systemctl status usb-gadget.service; journalctl -b -u usb-gadget.service\n  - run usb-gadget yourself: sudo usb-gadget\n  - scan for connected hosts: command -v nmap \u003e/dev/null 2\u003e\u00261 || sudo apt-get install -yqq nmap; nmap -sn 10.10.10.11-14\n  - check networking: systemctl status networking\n  - check dnsmasq service: systemctl status dnsmasq.service\n  - check dnsmasq config: dnsmasq --test\n  - stop dnsmasq service: sudo systemctl stop dnsmasq.service\n  - start dnsmasq manually: dnsmasq --no-daemon --log-queries\n```\n\nAs advised by the diagnosis script, you can also try:\n\n```shell\njournalctl -b -u usb-gadget.service\n```\n\n[![usb gadget log](docs%2Fusb-gadget-log.png)](./docs/usb-gadget-log.png)\n\nThis prints something like the following, which is quite handy when debugging\ncustom gadget functions:\n\n```text\nsystemd[1]: Starting Pi Hero USB Gadget...\nusb-gadget[642]: Setting up USB gadget pihero...\nusb-gadget[642]: Creating gadget pihero...\nusb-gadget[642]: Creating configuration c.1...\nusb-gadget[642]: Creating function ecm.usb0...\nusb-gadget[642]: Associating function ecm.usb0 with configuration c.1...\nusb-gadget[642]: Creating function acm.usb0...\nusb-gadget[642]: Associating function acm.usb0 with configuration c.1...\nusb-gadget[642]: Creating function mass_storage.usb0...\nusb-gadget[642]: Delegating creation of function mass_storage.usb0 to usb-gadget-custom...\nusb-gadget[664]: Creating custom function mass_storage.usb0 using inline script...\nusb-gadget[664]: Invoking /tmp/tmp.mrFN5Lqm7H mass_storage usb0 in functions/mass_storage.usb0...\nusb-gadget[668]: /tmp/tmp.mrFN5Lqm7H: line 12: lun.1/removable: No such file or directory\nusb-gadget[664]: ERROR: Invocation terminated with exit code 1.\nusb-gadget[664]: ERROR: Failed to execute script /tmp/tmp.mrFN5Lqm7H for function mass_storage.usb0.\nusb-gadget[642]: ERROR: The function mass_storage.usb0 failed to create. It won't be associated with configuration c.1.\nusb-gadget[642]: This is what functions/mass_storage.usb0 looked like:\nusb-gadget[642]:     Directory /sys/kernel/config/usb_gadget/pihero/functions/mass_storage.usb0\nusb-gadget[642]:     total 0\nusb-gadget[642]:     drwxr-xr-x 2 root root    0 Aug  6 23:40 lun.0/\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 stall\nusb-gadget[642]:\nusb-gadget[642]:     functions/mass_storage.usb0/lun.0:\nusb-gadget[642]:     total 0\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 cdrom\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 nofua\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 removable\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 ro\nusb-gadget[642]:     --w------- 1 root root 4.0K Aug  6 23:40 forced_eject\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 inquiry_string\nusb-gadget[642]:     -rw-r--r-- 1 root root 4.0K Aug  6 23:40 file\nusb-gadget[642]: Enabling gadget in /sys/kernel/config/usb_gadget/pihero... ✔︎\nsystemd[1]: Finished Pi Hero USB Gadget.\n```\n\nThe relevant line here is `/tmp/tmp.mrFN5Lqm7H: line 12: lun.1/removable: No such file or directory`.\nWhen you look closely, you can see that `lun.1` was used instead of `lun.0`.\n\n## Contributing\n\nWant to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. You\ncan also support this project by making\na [PayPal donation](https://www.paypal.me/bkahlert) to ensure this journey continues indefinitely!\n\nThanks again for your support, it is much appreciated! :pray:\n\n## License\n\nMIT. See [LICENSE](LICENSE) for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkahlert%2Fpihero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbkahlert%2Fpihero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbkahlert%2Fpihero/lists"}