{"id":17280276,"url":"https://github.com/akuli/mittari","last_synced_at":"2025-10-09T13:04:40.770Z","repository":{"id":219369306,"uuid":"741236070","full_name":"Akuli/mittari","owner":"Akuli","description":"Analog CPU and RAM usage meters for my computer","archived":false,"fork":false,"pushed_at":"2024-04-30T12:06:45.000Z","size":28923,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-31T16:18:22.024Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Akuli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-01-10T01:17:04.000Z","updated_at":"2024-04-30T12:06:46.000Z","dependencies_parsed_at":"2024-04-13T00:45:53.629Z","dependency_job_id":null,"html_url":"https://github.com/Akuli/mittari","commit_stats":null,"previous_names":["akuli/mittari"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akuli%2Fmittari","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akuli%2Fmittari/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akuli%2Fmittari/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akuli%2Fmittari/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Akuli","download_url":"https://codeload.github.com/Akuli/mittari/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245678901,"owners_count":20654738,"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-15T09:19:54.725Z","updated_at":"2025-10-09T13:04:35.730Z","avatar_url":"https://github.com/Akuli.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mittari\n\nhttps://github.com/Akuli/mittari/assets/18505570/8fe26e2d-5717-4242-8159-7ad8b30a4cea\n\nThis project is an analog CPU and RAM meter for my computer.\nIt involves woodworking, electronics, analog audio, digital audio, Python, tkinter, C, and a few other things.\n\nThe idea is taken from [this youtube video](https://www.youtube.com/watch?v=4J-DTbZlJ5I).\n\n![picture of internals](images/internals-high-level.jpg)\n\nThe meters are controlled by sending audio out through a USB sound card:\na louder audio makes a meter display a bigger value.\nThis turned out to be the easiest way to get data out of my computer.\nAlso, because the USB sound card outputs stereo audio,\nI conveniently get two channels (left and right) that I can use for the two meters.\nThis does mean that if I connect my headphones to the wrong place,\nI will hear a 1kHz sine wave.\n\n\n## Meters\n\n![picture of meters](images/meters.jpg)\n\n(Apparently they make current meters by adding a resistor to a voltage meter)\n\nThe meters are [this product from AliExpress](https://www.aliexpress.com/item/1005004735059319.html).\nI used the 5mA version, so that the meters would consume much less current\nthan the 500mA limit of USB 2.0.\n\n\n## Custom Scales\n\n![picture of CPU and RAM scales](images/scales.jpg)\n\nI scanned the original mA scale with a scanner,\ndrew my own scale on top of it,\nand then printed my scales onto paper and glued them on the back sides of the original scales.\nIn this repo, scales.odg is the LibreOffice drawing file.\n\nThe first gluing attempt was a failure.\nThe glue basically went through the paper and made it look darker.\nTo work around this, I applied glue only to the bottom,\nand relied on the plastic case to hold down the paper elsewhere.\n\n\n## Woodworking\n\n![picture of wood part front side](images/wood-front.jpg)\n\n![picture of wood part back side](images/wood-back.jpg)\n\nI fitted the meters into a small leftover piece of spruce\nusing mostly a table saw, a drill press and a chisel.\nI also cut slots for the LEDs.\n\nAfter having the wooden part in my apartment for a few days,\nit had dried and the meters didn't fit anymore.\nI widened the meter holes by about 1mm in the direction across the grain.\n\n\n## Power Cable and Fuse\n\n![picture of modified USB extension cord](images/usb-cable.jpg)\n\nI took the shortest USB 2.0 extension cord I found, sliced it open,\nand soldered more wires onto it to get 5V power.\nDoing this with USB 2.0 is super easy, because USB 2.0 cords have only 4 wires inside:\n+5V (red), ground (black), and two data pins (D+ and D-).\n\nI used a lot of shrink tube, because I don't want to break my computer by accidentally shorting these.\n\nOne end of the extension cord plugs into my computer (through a longer extension cord),\nand the other end is for the USB sound card.\n\nThe black thingy at the end of the red cable is one half of\n[this fuse holder that I already had](https://www.biltema.fi/en-fi/car---mc/electrical-system/fuses/line-fuse-holder-5-x-20-mm-2000048666).\nI am using a fast 315mA fuse, because it works and I already had it.\nI also tried a 63mA fuse, because the circuit seems to consume less than 50mA,\nbut it added too much resistance and the meters did not go all the way to 100%.\n\n\n## USB Sound Card\n\n![picture of sound card](images/usb-sound-card.jpg)\n\nI got this about 10 years ago. I don't remember why or where.\nAliExpress sells very similar USB sound cards for about 2 euros each (includes shipping).\n\n\n## Circuit Board\n\n![picture of circuit board](images/board.jpg)\n\nThe board itself is [stripboard](https://en.wikipedia.org/wiki/Stripboard).\nThe black marks indicate where I cut the strips of copper on the other side.\n\nI assembled this board almost entirely out of components I already had.\nI think I only bought super-bright red LEDs.\nThe thing with a thick red cable is the other half of the fuse holder.\n\nEach row of LEDs is yellow-red-yellow-red-yellow,\nand the LEDs are aimed at the meters.\nIn hindsight, the black shrink tube around outermost LED legs is unnecessary.\nI thought they would prevent the LED legs from touching the angle brackets that hold the board,\nbut when assembling this,\nI ended up with a couple millimeters between the angle brackets and LED legs.\n\nThe audio cable is taken from cheap and broken earbuds.\nThe wires are covered in some kind of colorful insulation stuff that makes them difficult to solder.\nIt seems to burn away with a high temperature (I think I used 370-400 celsius) and a lot of time (15+ seconds).\n\nThe `layout.diy` file in this repo is a [DIY Layout Creator](https://diy-fever.com/software/diylc/) drawing of the board.\n\n\n## Circuit Design\n\n![circuit diagram](images/circuit.png)\n\nI designed an analog circuit to drive the meters and LEDs,\nbecause I haven't yet learned to throw a microcontroller at every electronics problem.\nHere is **one half** of the circuit, enough to drive one meter and one row of LEDs.\nThe other half is similar.\n\nThe repository contains [a circuitjs file](./mittari.circuitjs.txt)\nthat you can open with [circuitjs](https://www.falstad.com/circuit/circuitjs.html).\nAlternatively, if you don't want to clone this repository,\ncopy the file's content and paste it to \"Import from Text\" in circuitjs.\n\nHere is a walk-through of the circuit, from left to right:\n\n- The audio signal goes through a high-pass filter (100nF cap and 56k resistor).\n- The two diodes (1N4148) limit the input voltage to about +-0.7V.\n- The op-amp (UA798TC) is basically a non-inverting amplifier with a gain of about 100,\n    but because of the diode at its output,\n    it can only increase the output voltage, not decrease it.\n    This causes the circuit to compute the maximum (peak) value of the audio signal.\n    The small 1k resistor represents the internal output resistance of the op-amp.\n- The 100nF capacitor after the op-amp remembers the maximum voltage of the input signal.\n- The current meter (bottom of picture) is driven through a BC549C transistor,\n    connected as a voltage follower, and a 470 ohm series resistor.\n- The LED transistors use [this transistor trick](https://electronics.stackexchange.com/q/164068)\n    to turn on either yellow or red LEDs depending on the voltage.\n    The two transistors basically act as a comparator,\n    comparing the output of the op-amp to 3V given by the voltage divider on the right.\n    The red LEDs begin to turn at about 75%,\n    and there's almost no yellow light when a meter is displaying 100%.\n\nFor some reason, the 100nF caps\nget charged to 270mV on one channel and 400mV on the other channel\nwhen there is no audio coming in.\nI'm not sure why that happens, but it doesn't matter\nas long as these weird voltages aren't enough to turn on the transistors.\n\nWith a 1kHz input signal, the 100nF capacitors need to remember the voltage\naccurately enough for about 1ms.\nIn reality, this is far from accurate.\nFor example, when a meter displays 100%, the capacitor's voltage bounces between about 2.75V and 3.25V.\nThis doesn't really matter though, because the bouncing happens at 1kHz\nand the meters cannot physically move back and forth at a 1kHz frequency.\nAlso, I need to compensate for inaccuracy in software anyway,\nbecause the AliExpress current meters are horribly inaccurate.\n\nHere are some improvements I might make if I was building this again:\n\n- Remove the high pass filter and protection diodes. They are unnecessary.\n- Use a larger capacitor.\n    This would make the circuit easier to debug, because the voltage would bounce around less.\n    It would also make the circuit less dependent on transistor current gain (beta) values.\n- Add a resistor to the base of the transistor that drives the red LEDs,\n    so that the capacitor's voltage can raise higher than the transistor's base.\n    In the version I built, the 470ohm current meter resistor was chosen\n    so that the meters reach their maximum value just before the transistor limits the voltage.\n- Test the circuit with 4.75V and 5.25V, and fix it if it doesn't work.\n    These are the smallest and biggest allowed \"5V\" voltages in the USB spec.\n\n\n## Layout\n\n![layout](images/layout.png)\n\nI laid out the components onto stripboard using\n[DIY Layout Creator](https://diy-fever.com/software/diylc/).\nIt is not the best possible software for doing this, but it works.\nThe DIYLC file is `layout.diy` in this repository.\n\n\n## Supported operating system\n\nThe software reads `/proc/stat` and `/proc/meminfo` (both Linux-specific) to get CPU and RAM usage,\nand sends audio data to an `aplay` subprocess (also Linux-specific).\nThis means that the software will not work on anything other than Linux.\n\nThe advantage is that there are no dependencies except development tools and Python's standard library.\nTo me, this seems like a better option than supporting platforms that I won't use anyway.\nIf I added Windows or MacOS support, it would probably be broken most of the time.\n\n\n## Python and Tkinter\n\n![config GUI](images/config-screenshot.png)\n\nI made an ugly but useful Python script with a tkinter GUI.\nThe main purpose is compensating for electronics inaccuracies in software.\nThere are several inaccuracies:\n- Transistors need about 0.6V to turn on.\n- The AliExpress current meters are inaccurate.\n- The circuit depends on the current gain (beta) of the transistors.\n- I used +-5% resistors and capacitors, and also a couple +-10% capacitors.\n\nBut none of this matters if the software can output the correct audio volumes\nto set the meters to the right places.\n\nEach slider sets the audio volume used to move the meter to a given position.\nFor example, the 20% sliders should be adjusted so that the meter displays 20%\nwhen that slider is hovered.\nThen, to display a value like 27%, the software will output a sine wave\nwhose volume is a weighted average of the positions of the 20% and 30% sliders.\nIn other words, it uses linear interpolation.\nAs you hover or drag the sliders, the meter shows the value set by the slider,\nso that you know where the slider should be.\n\nRunning the config script:\n\n```\n$ sudo apt install python3-tk alsa-utils\n$ python3 config.py my-mittari-config.conf\n```\n\nHere `my-mittari-config.conf` is the name of a config file\nthat is in a completely non-standard format.\nIt will be created if it doesn't exist.\nThe repository contains [example-config.conf](./example-config.conf),\nso you can get an idea of what a config file looks like without running anything.\n\nDeveloping the config script:\n\n```\n$ python3 -m venv env\n$ source env/bin/activate\n$ pip install -r requirements-dev.txt\n$ mypy config.py        # type checker\n$ python3 -m pytest     # run tests\n```\n\n\n## C\n\nOnce I have a config file, I run a C program to display my CPU and memory usage:\n\n```\n$ sudo apt install gcc make\n$ make\n$ ./mittari my-mittari-config.conf\n```\n\nI originally wrote this part in Python,\nbut I rewrote it in C because the Python version always consumed a couple percent of CPU.\n\nThe C program spawns an `aplay` subprocess and then feeds audio data to its stdin in chunks of 0.1 seconds.\nThe 0.1 can be changed by editing the config file manually.\n\nI made sure to handle situations where `aplay` or my C program lag:\n- If my C program lags, `aplay` will stop playing for a moment and print a warning.\n    This is fine, but unlikely to ever happen in practice.\n    My C program only writes a chunk of audio data every 0.1 seconds,\n    so it is idle most of the time.\n- If `aplay` lags, my C program will get stuck at writing data to its stdin until the lag is over.\n    To ensure that this happens, I\n    [set the pipe buffer size as small as possible](https://stackoverflow.com/a/14371183).\n    This is important, because if my C program is allowed to just write more stuff,\n    it can write several seconds of audio data while `aplay` is stuck,\n    and once `aplay` is a few seconds behind,\n    the meters update with a few seconds of lag.\n\nI also take lags into account when timing the 0.1 seconds:\n- Time between the sleeps is subtracted from the sleep time,\n    so if the C program spends 0.01 seconds doing something between two sleeps,\n    then the second sleep will be 0.09 seconds instead of 0.1 seconds.\n- If the C program spends more than 0.1 seconds between two sleeps,\n    then the second sleep is skipped entirely.\n\nI used the SIGSTOP and SIGCONT signals to test how lags are handled:\n\n```\n$ pkill -STOP aplay\n$ pkill -CONT aplay\n$ pkill -STOP mittari\n$ pkill -CONT mittari\n```\n\nAfter causing lags, I started and stopped an infinite loop to see how quickly the CPU usage updates:\n\n```\n$ while true; do :; done\n```\n\n\n## Installation\n\nFigure some way to run the `mittari` executable when the system boots.\nRemember to pass the path to your config file as an argument to it.\nFor example, you could add a command to `.profile` or `.xsessionrc`,\nso the meters start working when you log in.\n\nFor some reason, I wanted the meters to start working before I even log in.\nI placed the executable and config file to a new folder `/opt/mittari`.\nThen I created a user `mittari` with `sudo adduser --system mittari`\nand added it to the `audio` group,\nhoping that audio would continue to work for my `akuli` user.\nI then added `su -s /bin/bash mittari -c \"/opt/mittari/mittari /opt/mittari/config.conf\"` to `/etc/rc.local`.\nIf I had `systemd`, I probably would have created a service file instead.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuli%2Fmittari","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakuli%2Fmittari","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakuli%2Fmittari/lists"}