{"id":20261049,"url":"https://github.com/datarootsio/fresh-coffee-listener","last_synced_at":"2025-09-04T05:35:13.095Z","repository":{"id":46828318,"uuid":"398231881","full_name":"datarootsio/fresh-coffee-listener","owner":"datarootsio","description":"Using a raspberry pi, we listen to the coffee machine and count the number of coffee consumption","archived":false,"fork":false,"pushed_at":"2021-09-23T08:57:56.000Z","size":1463,"stargazers_count":55,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-28T20:52:00.498Z","etag":null,"topics":["coffee-machine","counter","mfcc-features","python","raspberrypi","raspbian","sound-processing","systemd"],"latest_commit_sha":null,"homepage":"","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/datarootsio.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":"2021-08-20T09:59:28.000Z","updated_at":"2025-01-08T15:20:41.000Z","dependencies_parsed_at":"2022-09-03T21:22:44.938Z","dependency_job_id":null,"html_url":"https://github.com/datarootsio/fresh-coffee-listener","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/datarootsio/fresh-coffee-listener","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarootsio%2Ffresh-coffee-listener","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarootsio%2Ffresh-coffee-listener/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarootsio%2Ffresh-coffee-listener/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarootsio%2Ffresh-coffee-listener/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datarootsio","download_url":"https://codeload.github.com/datarootsio/fresh-coffee-listener/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datarootsio%2Ffresh-coffee-listener/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273556192,"owners_count":25126515,"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","status":"online","status_checked_at":"2025-09-04T02:00:08.968Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["coffee-machine","counter","mfcc-features","python","raspberrypi","raspbian","sound-processing","systemd"],"created_at":"2024-11-14T11:23:40.029Z","updated_at":"2025-09-04T05:35:13.043Z","avatar_url":"https://github.com/datarootsio.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![maintained by dataroots](https://img.shields.io/badge/maintained%20by-dataroots-%2300b189)](https://dataroots.io)\n ![](https://media-exp1.licdn.com/dms/image/C4D1BAQFJFecNiY6xNA/company-background_10000/0/1606894615032?e=1628604000\u0026v=beta\u0026t=hNYzs9y3EA-620Ck8ip1QaZc77eXlH1ZUl-E-sLI6wo \"Logo\")\n\n# Fresh-Coffee-Listener\n\nA typical datarootsian consumes high-quality fresh coffee in their office environment. The board of dataroots had\na very critical decision by the end of 2021-Q2 regarding coffee consumption. From now on, the total number of coffee\nconsumption stats have to be audited live via listening to the coffee grinder sound in Raspberry Pi, because why not? \nCheck stats from [here](https://app.cumul.io/s/coffeeometer-lejpayjm3rdjgtiu).\n\n## Overall flow to collect coffee machine stats\n1. Relocate the Raspberry Pi microphone just next to the coffee machine\n2. Listen and record environment sound at every 0.7 seconds\n3. Compare the recorded environment sound with the original coffee grinder sound and measure the \n   Euclidean distance\n4. If the distance is less than a threshold it means that the coffee machine has been started and a \n   datarootsian is grabbing a coffee\n5. Connect to DB and send timestamp, office name, and serving type to the DB in case an event is detected (\n   E.g. 2021-08-04 18:03:57, Leuven, coffee\n   )\n   \n## Raspberry Pi Setup\n![](coffee_machine.JPG \"coffee machine\")\n\n1. **Hardware**: Raspberry Pi 3b\n2. **Microphone**: External USB microphone (doesn't have to be a high-quality one). We also bought a \n   microphone with an audio jack but apparently, the Raspberry Pi audio jack doesn't have an input. So, don't do the same mistake and just go for the USB one :)\n3. **OS**: Raspbian OS\n4. **Python Version**: Python 3.7.3. We used the default Python3 since we don't have any other python projects in the same Raspberry Pi. You may also create a virtual environment.\n   \n## Detecting the Coffee Machine Sound\n1. In the `sounds` folder, there is a `coffee-sound.m4a` file, which is the recording of the coffee machine grinding sound for 1 sec. You need to replace this recording with your coffee machine recording. It is very important to note that record the coffee machine sound with the external microphone that you will use in Raspberry Pi to have a much better performance.\n2. When we run `detect_sound.py`, it first reads the `coffee-sound.m4a` file and extracts its [MFCC](https://en.wikipedia.org/wiki/Mel-frequency_cepstrum) features.\nBy default, it extracts 20 MFCC features. Let's call these features `original sound features`\n3. The external microphone starts listening to the environment for about 0.7 seconds with a 44100 sample rate. Note\nthat the 44100 sample rate is quite overkilling but Raspberry Pi doesn't support lower sample rates out of the box.\nTo make it simple we prefer to use a 44100 sample rate.\n4. After each record, we also extract 20 `MFCC` features and compute the [Euclidean Distance](https://en.wikipedia.org/wiki/Euclidean_distance#:~:text=In%20mathematics%2C%20the%20Euclidean%20distance,being%20called%20the%20Pythagorean%20distance.)\nbetween the `original sound features` and `recorded sound features`.\n5. We append the `Euclidean Distance` to a [python deque object](https://docs.python.org/3/library/collections.html#collections.deque)\nhaving size 3. \n6. If the maximum distance in this deque is less than `self.DIST_THRESHOLD = 85`, then it means that there is a \ncoffee machine usage attempt. Feel free to play with this threshold based on your requirements. You can simply\ncomment out `line 66` of `detect_sound.py` to print the deque object and try to select the best threshold. We prefer\nto check 3 events (i.e having deque size=3) subsequently to make it more resilient to similar sounds.    \n7. Go back to step 3, if the elapsed time is \u003c 12 hours. (Assuming that the code will run at 7 AM and ends at 7 PM \n   since no one will be at the office after 7 PM)\n8. Exit\n\n## Scheduling the coffee listening job\nWe use a systemd service and timer to schedule the running of `detect_sound.py`. Please check `coffee_machine_service.service` \nand `coffee_machine_service.timer` files. This timer is enabled in the `makefile`. It means that even if you reboot your\nmachine, the app will still work. \n\n#### coffee_machine_service.service\nIn this file, you need to set the correct `USER` and `WorkingDirectory`. In our case, our settings are; \n\n```shell\nUser=pi\nWorkingDirectory= /home/pi/coffee-machine-monitoring\n```\nTo make the app robust, we set `Restart=on-failure`. So, the service will restart if something goes wrong in the app. (E.g power outage, someone plugs out the microphone and plug in again, etc.). This service will trigger `make run`\nthe command that we will cover in the following sections.\n\n#### coffee_machine_service.timer\nThe purpose of this file is to schedule the starting time of the app. As you see in;\n```shell\nOnCalendar=Mon..Fri 07:00\n```\nIt means that the app will work every weekday at 7 AM. Each run will take 7 hours. So, the app will complete \nlistening at 7 PM.\n\n## Setup a PostgreSQL Database\nYou can set up a PostgreSQL database at any remote platform like an on-prem server, cloud, etc. It is not advised to install it to\nRaspberry Pi.\n1. Install and setup a PostgreSQL server by following the [official documentation](https://www.postgresql.org/docs/current/tutorial-install.html)\n   \n2. Create a database by typing the following command to the PostgreSQL console and replace `DB_NAME` with your database name;\n   ```\n   createdb DB_NAME\n   ```\n   If you got an error, check [here](https://www.postgresql.org/docs/current/tutorial-createdb.html)\n   \n3. Create a table by running the following query in your PostgreSQL console by replacing `DB_NAME` and `TABLE_NAME` with\nyour own preference;\n   ```postgresql\n   CREATE TABLE DB_NAME.TABLE_NAME (\n       \"timestamp\" timestamp(0) NOT NULL,\n       office varchar NOT NULL,\n       serving_type varchar NOT NULL\n   );\n   ```\n4. Create a user, password and give read/write access by replacing `DB_USER`, `DB_PASSWORD`, `DB_NAME` and `DB_TABLE`\n   ```postgresql\n   create user DB_USER with password 'DB_PASSWORD';\n   grant select, insert, update on DB_NAME.DB_TABLE to DB_USER;\n   ```\n\n## Deploying Fresh-Coffee-Listener app\n1. **Installing dependencies**: If you are using an ARM-based device like Raspberry-Pi run \n   ```shell\n   make install-arm\n   ```\n   For other devices having X84 architecture, you can simply run\n   ```shell\n   make install\n   ```\n\n2. **Set Variables in makefile**\n   -  `COFFEE_AUDIO_PATH`: The absolute path of the original coffee machine sound (E.g. `/home/pi/coffee-machine-monitoring/sounds/coffee-sound.m4a`)\n   -  `SD_DEFAULT_DEVICE`: It is an integer value represents the sounddevice input device number. To find your external device number, run\n   `python3 -m sounddevice` and you will see something like below;\n      ```shell\n         0 bcm2835 HDMI 1: - (hw:0,0), ALSA (0 in, 8 out)\n         1 bcm2835 Headphones: - (hw:1,0), ALSA (0 in, 8 out)\n         2 USB PnP Sound Device: Audio (hw:2,0), ALSA (1 in, 0 out)\n         3 sysdefault, ALSA (0 in, 128 out)\n         4 lavrate, ALSA (0 in, 128 out)\n         5 samplerate, ALSA (0 in, 128 out)\n         6 speexrate, ALSA (0 in, 128 out)\n         7 pulse, ALSA (32 in, 32 out)\n         8 upmix, ALSA (0 in, 8 out)\n         9 vdownmix, ALSA (0 in, 6 out)\n        10 dmix, ALSA (0 in, 2 out)\n      * 11 default, ALSA (32 in, 32 out)\n      ```\n   It means that our default device is `2` since the name of the external device is `USB PnP Sound Device`. So, we will \n   set it as `SD_DEFAULT_DEVICE=2` in our case.\n   - `OFFICE_NAME`: it's a string value like `Leuven office`\n   - `DB_USER`: Your PostgreSQL database username\n   - `DB_PASSWORD`: the password of the specified user\n   - `DB_HOST`: The host of the database\n   - `DB_PORT`: Port number of the database\n   - `DB_NAME`: Name of the database\n   - `DB_TABLE`: Name of the table\n   \n3. **Sanity check**: Run `make run` to see if the app works as expected. You can also have a coffee to test whether it captures \n   the coffee machine sound.\n   \n4. **Enabling systemd commands to schedule jobs**: After configuring `coffee_machine_service.service` and \n`coffee_machine_service.timer` based on your preferences, as shown above, run to fully deploy the app;\n   ```shell\n   make run-systemctl\n   ```\n5. Check the `coffee_machine.logs` file under the project root directory, if the app works as expected\n6. Check service and timer status with the following commands\n   ```shell\n   systemctl status coffee_machine_service.service\n   ```\n   and\n   ```shell\n   systemctl status coffee_machine_service.timer\n   ```\n   \n## Having Questions / Improvements ?\nFeel free to create an issue and we will do our best to help your coffee machine as well :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatarootsio%2Ffresh-coffee-listener","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatarootsio%2Ffresh-coffee-listener","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatarootsio%2Ffresh-coffee-listener/lists"}