{"id":17336953,"url":"https://github.com/2m/zbap","last_synced_at":"2025-04-14T18:41:20.060Z","repository":{"id":7097604,"uuid":"8389333","full_name":"2m/zbap","owner":"2m","description":"Zero Button Audiobook Player based on Rapberry Pi","archived":false,"fork":false,"pushed_at":"2022-06-07T08:40:34.000Z","size":449,"stargazers_count":18,"open_issues_count":0,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-06T09:31:47.349Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-02-24T10:30:59.000Z","updated_at":"2024-06-19T21:38:54.000Z","dependencies_parsed_at":"2022-08-28T20:11:01.767Z","dependency_job_id":null,"html_url":"https://github.com/2m/zbap","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2m%2Fzbap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2m%2Fzbap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2m%2Fzbap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2m%2Fzbap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2m","download_url":"https://codeload.github.com/2m/zbap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248938197,"owners_count":21186359,"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":[],"created_at":"2024-10-15T15:33:15.693Z","updated_at":"2025-04-14T18:41:20.027Z","avatar_url":"https://github.com/2m.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Zero Button Audiobook Player\n============================\n\n[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/2m/zbap?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n[Demo video]\n\nThis project is based on Raspberry Pi and hugely inspired by [The One Button Audiobook player]. I too have grandmother who is visually impaired and loves listening to audiobooks. Until now she has been doing this using old DVD player, which worked quite well, but that player does not save its state. So every time its turned off and back on it begins to play audiobook from the beginning.\n\nSo naturally this was a great opportunity for a Raspberry Pi project. However I went a little bit further and did not add any buttons at all. This audiobook player can be controlled using simple HTTP queries (mostly for debugging) or using NFC tags.\n\nSo the plan is to add some NFC tag stickers on empty DVD or CD cases. Actually anything might work which is quite bulky. So every NFC tag (or empty CD case in this case) references some audiobook in the internal player memory. When someone puts a tag over the player, it starts playing respective audiobook from its last state.\n\nThis player saves its state every couple of seconds. So whenever my grandmother gets bored of listening to it she can plug the player out of the mains socket. When the player is turned back on, it starts right from its last saved state.\n\nI believe using this kind of technology will will present the smallest learning curve (if any). I will see what my grandmother thinks of it after couple of months using it.\n\nHow it came about\n=================\nThis is my first Raspberry Pi project. So here I will try to enumerate every step that I took to make this project be.\n\nHardware\n--------\nI got a Raspberry Pi for this project from [ModMyPi]. I also bought a case, SD to microSD card adapter and HDMI to DVI adapter from there.\n\nIt took some time to locate a suitable NFC reader. It had to be quite small so it fitted into RPi case. I chose [PN532 NFC RFID module kit] which I saw mentioned in couple of SIB Vision blog posts.\n\nFirstly [this][NFC/RFID for Beagleboard xm with Java] blog post helped me to change NFC module protocol from default _I2C_ to _HSU_ (or _UART_). Secondly, [another post][NFC Reader with RaspberryPi GPIO] mentioned everything I needed to know to successfully connect this NFC module to Raspberry Pi.\n\nSo I unsoldered 0 Ohm resistor from _bit 1 of HIS0 pin_ and then shortened _bit 0 of HIS0 pin_, which was harder than it sounds because of my gigantic soldering iron. Next I tweaked those mentioned config files and connected NFC module to RPi. It was quite simple. I had some problems installing _libnfc_ but more on that later.\n\nSoftware\n--------\nI chose to use Python for this project, which comes already in a [Rasbian Weezy] which I installed into microSD card and successfully booted RPi for the first time.\n\nI am quite limited in some parts of working in Linux. For example I was not quite sure how to configure network on Raspberry Pi. This is what helped me to [Share Internet Connection with Linux] from my Windows PC.\n\nFor music playing part I installed [MPD] using a tutorial from [here][Installing MPD] and also installed [Python MPD2]. I had some problems with this. Mainly some commands (_seek_ for example) in Python did not work. I believe the problem was caused because _apt-get_ installed _0.16.0_ version of MPD and Python MPD2 already bumped its support to _MPD_ version _0.17.0_ which maybe broke some backwards compatibility.\n\nThere are couple of distinctive logical modules in this project:\n\n* audio file player;\n* state saver;\n* web interface;\n* nfc interface.\n\nAll of these need to interchange messages when some event occurs. I figured [Actor Model] should work here quite well and installed [Pykka] which is a python implementation of actor model. I am quite new (self taught and worked only on toy projects) to actors, so I am not sure if I used Pykka in a best way. However my code seems to work and it is not very ugly.\n\nNFC part of this project is handled by the open source [libnfc]. To install (compile) this library first I followed an article from Adafruit on [NFC on Raspberry Pi]. However that article is a little bit outdated and _libnfc_ has to be installed a little bit differently from version _1.7.0_. As members of libnfc forum pointed out [here][libnfc forum post] and [here][libnfc forum post #2] before compilation libnfc must be configured with only one parameter. ```./configure --with-drivers=pn532_uart``` Then after ```sudo make install``` a configuration file for Raspberry Pi must be copied to a directory which is checked by libnfc on startup. ```sudo cp contrib/libnfc/pn532_uart_on_rpi.conf.sample /usr/local/etc/nfc/devices.d/pn532_uart_on_rpi.conf``` Make sure to create target directory before issuing this command. After these steps a set of commands can be used to debug or check whether libnfc works as expected.\n\n* ```LIBNFC_LOG_LEVEL=3 nfc-list``` Enabling debug with environment variable is helpful to determine which directories libnfc is scanning for configuration files.\n* ```nfc-scan-device -i -v``` Will list all devices detected by libnfc.\n* ```nfc-poll``` Will listen for any NFC tags for 30 seconds and will print tag information if it detects any.\n\nThat is pretty much it. All of these parts combined make a pretty neat Zero Button Audiobook Player. :)\n\nI used merged MP3 audiobooks. However after merging MPD was not able to play past the first part. I used [mp3val](http://mp3val.sourceforge.net/) to clean and fix merged MP3 files.\n\nSoftware Architecture\n=====================\nHere I will list logical modules of the software and their relations. All modules are mostly _pykka actor proxy objects_. So whenever you see that one actor is calling a method of other actor, it really is not the case. Behind the scenes a message is sent from one actor to another. So all these calls are asynchronous.\n\n[Zbap.py](Zbap.py)\n------------------\nThe main project file which creates and initializes all actors. It also from time to time gives a tick to actors which need to do periodic tasks. The whole project is started by executing ```python Zbap.py```.\n\nThis _ticking actors_ implementation is one place where I think is implemented wrongly according to the Actor Model. At first these actors had a infinite loop inside them, but in this case these actors would continue looping even if main program was killed. So to have better control of the program flow, I moved the loop to the [Zbap.py](Zbap.py) file.\n\n[MpdActor.py](MpdActor.py)\n--------------------------\nThis actor connects to MPD using mpd-python2 and is responsible of controlling MPD. It has methods such as ```getCurrentSong``` and ```playByNameFrom``` which are quite self documenting. These methods are for other actors to call.\n\n[StateActor.py](StateActor.py)\n------------------------------\nActor which saves currently playing song and the amount of seconds played from the beginning every so often. State is saved to [data/state.json](data/state.json) file. It also provides ```playFromLastState``` method for other actors which when called starts playing an audio file from its last saved state.\n\n[TagActor.py](TagActor.py)\n--------------------------\nActor which translates between audio file _tag_ and its file name. The mapping between audio file names and tags is provided in [data/tags.py](data/tags.py) file.\n\n[WebActor.py](WebActor.py)\n--------------------------\nThis actor provides HTTP interface to the audiobook player. This is really helpful when debugging given that HTTP calls can be made using a web browser from any computer connected to the same network as Raspberry Pi. Available commands:\n\n* ```http://\u003craspberry_pi_ip\u003e:8080/play/\u003ctag\u003e``` Starts playing a song identified by a tag from its last known state.\n* ```http://\u003craspberry_pi_ip\u003e:8080/play/\u003ctag\u003e/fromStart``` Starts playing a song identified by a tag from the start.\n\n[NfcActor.py](NfcActor.py)\n--------------------------\nActor which periodically checks if there is a NFC tag nearby by calling ```nfc-list``` command. If NFC tag is found, this actor parses the tag from the command output and gives it to the [TagActor.py](TagActor.py) asking to play the audio file.\n\n[Demo video]: http://www.youtube.com/watch?v=PfXmEMPt9ws\n[The One Button Audiobook player]: http://blogs.fsfe.org/clemens/2012/10/30/the-one-button-audiobook-player/\n[ModMyPi]: https://www.modmypi.com/\n[PN532 NFC RFID module kit]: http://www.elechouse.com/elechouse/index.php?main_page=product_info\u0026cPath=90_93\u0026products_id=2205\n[NFC/RFID for Beagleboard xm with Java]: http://blog.sibvisions.com/2012/11/26/nfcrfid-for-beagleboard-xm-with-java/\n[NFC Reader with RaspberryPi GPIO]: http://blog.sibvisions.com/2013/01/04/nfc-reader-with-raspberrypi-gpio/\n[Rasbian Weezy]: http://www.raspberrypi.org/downloads\n[Share Internet Connection with Linux]: http://blog.creativeitp.com/posts-and-articles/windows/share-windows-internet-connection-with-linux/comment-page-1/\n[MPD]: http://mpd.wikia.com/wiki/Music_Player_Daemon_Wiki\n[Installing MPD]: http://crunchbang.org/forums/viewtopic.php?id=4686\n[Python MPD2]: https://github.com/Mic92/python-mpd2\n[Actor Model]: http://en.wikipedia.org/wiki/Actor_model\n[Pykka]: https://github.com/jodal/pykka\n[libnfc]: https://code.google.com/p/libnfc/\n[NFC on Raspberry Pi]: http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/overview\n[libnfc forum post]: http://www.libnfc.org/community/topic/924/no-nfc-device-when-using-libnfc-170-rc5-on-raspberry-pi/\n[libnfc forum post #2]: http://www.libnfc.org/community/topic/913/no-nfc-device-found-with-libnfc170rc4-on-raspberry-pi/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2m%2Fzbap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2m%2Fzbap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2m%2Fzbap/lists"}