1
0

Compare commits

..

10 Commits

Author SHA1 Message Date
29402e477c Add missing link to RGB Mixer talk 2024-10-07 20:55:08 +02:00
95e5cc6e17 Fix Atom feed path 2024-10-07 20:55:08 +02:00
7f1286f620 Hadog strwaberry special 2024-10-07 20:55:08 +02:00
62457781e5 Improve search script 2024-10-07 20:55:08 +02:00
aec76798e0 Add local content 2024-10-07 20:55:08 +02:00
df0680e756 Align "All Posts" button to the right 2024-05-06 12:24:42 +02:00
8ace90578e Add favicon 2024-01-26 17:12:11 +01:00
4fd68a25ff Remove redundant <p> tag 2024-01-25 20:18:56 +01:00
f4df8d0d1d Rename post overview to search 2024-01-19 10:50:17 +01:00
c8e14ca3e4 Clean external links 2024-01-19 10:50:17 +01:00
53 changed files with 1574 additions and 13 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
*.swp *.swp
public public
content/posts/*/tmp
content/posts/00-*

View File

@ -2,10 +2,7 @@ base_url = "https://em.0x45.cz"
title = "Emil Miler" title = "Emil Miler"
compile_sass = true compile_sass = true
build_search_index = false build_search_index = false
generate_feeds = true
generate_feed = true
feed_filename = "atom.xml"
feed_limit = 10
taxonomies = [ taxonomies = [
{name = "categories", feed = false} {name = "categories", feed = false}
@ -15,12 +12,15 @@ taxonomies = [
highlight_code = true highlight_code = true
highlight_theme = "kronuz" highlight_theme = "kronuz"
smart_punctuation = true smart_punctuation = true
external_links_target_blank = true
external_links_no_follow = true
external_links_no_referrer = true
[extra] [extra]
nav = [ nav = [
{title = "Index", path = "/"}, {title = "Index", path = "/"},
{title = "About", path = "/about/"}, {title = "About", path = "/about/"},
{title = "Posts", path = "/posts/"}, {title = "Search", path = "/posts/"},
{title = "Categories", path = "/categories/", mobile_only = true} {title = "Categories", path = "/categories/", mobile_only = true}
] ]
latest_posts_count = 3 latest_posts_count = 3

43
content/about.md Normal file
View File

@ -0,0 +1,43 @@
+++
title = "About"
[extra]
notoc = true
+++
This is my personal website mainly used for technical articles about problems and projects I am working on.
It is generated to static HTML via [Zola](https://www.getzola.org/).
## Contact me
- [em@0x45.cz](mailto:em@0x45.cz)
- [@irungentoo](https://t.me/irungentoo) on Telegram
- PGP: [0x453A7AE1754BFED2](https://keys.openpgp.org/vks/v1/by-fingerprint/3B08B7B5F00CCB0370EE3E71453A7AE1754BFED2)
## Work
My primary employment is at [SUSE](https://www.suse.com) as a security QA engineer. I also work (or have worked) as a teacher at several Prague schools, mainly at [Gymnázium Jana Keplera](https://gjk.cz/).
## Projects
Some of my project are published directly at this website or in Git:
- [git.0x45.cz/em](https://git.0x45.cz/em)
- [git.microlab.space/em](https://git.microlab.space/em)
- [github.com/realcharmer](https://github.com/realcharmer)
Many of my projects and activities can also be found at [microlab.space](https://microlab.space), which is a student group at our university (founded by me in 2018) focused on all kinds of technology related projects and research.
## Public speaking
These are all existing recordings of some of my talks and presentations, most of which happened at [InstallFest](https://installfest.cz/if22/) and [LinuxDays](https://www.linuxdays.cz/2021/) in Prague, though all of them are only in Czech. Some are very old and the quality is far from good.
- [Instalace FHD IPS displeje na ThinkPad X230](https://www.youtube.com/watch?v=oLWDE_mxJP0)
- [>install gentoo](https://www.youtube.com/watch?v=KC_QrgJ8mBo)
- [Proč si nepamatovat hesla a co jsou to password managery](https://www.youtube.com/watch?v=jlUO3fXQzQY)
- [Základy šifrování s GnuPG](https://www.youtube.com/watch?v=uEGvy0od8nM)
- [Modifikace strojů ThinkPad T430 a X230](https://www.youtube.com/watch?v=60o5ZVQCPcw)
- [Jak si vyrobit použitelný laptop -- Modifikace ThinkPadů X230 a T430](https://www.youtube.com/watch?v=R_SXGbItqbI)
- [Cesta z pekla -- Instalujeme vlastní BIOS na ThinkPad x230](https://www.youtube.com/watch?v=03G4MchxqYA)
- [PGP Key Signing Party](https://www.youtube.com/watch?v=rDMCPtjPuGo)
- [RGB Mixer](https://ftp.microlab.space/prednasky/rgb-mixer.mp4)

View File

@ -0,0 +1,24 @@
+++
title = "101, I Salute You"
date = 2024-05-06
[taxonomies]
categories = ["Culture"]
[extra]
author = "Emil Miler"
+++
There once existed a singular establishment known as "101," a place that, though no longer standing, will forever be enshrined in the memories of those fortunate -- or perhaps unfortunate -- enough to have crossed its threshold. Its walls witnessed many a tale of intrigue, mischief, and debauchery, none of which could be considered anything but extraordinary.
<!-- more -->
Over the years, a colorful array of characters passed through its doors, none leaving without a story to tell. Barroom brawls erupted without warning, drinks were consumed with reckless abandon, and, as if by some unspoken agreement, the usual conventions of society were all but abandoned. Anything and everything was permissible.
It was on the final night of the bar's existence that I found myself delivered, in the most peculiar fashion, in the boot of a car, directly into the midst of a celebration that shuddered on the edge of chaos. Those who had elected to remain at home would soon regret their decision, for they missed an evening unlike any other. By night's end, I had lost half of my trousers, my trusted guitar chordbook had inexplicably turned to liquid, and much of the revelry and quarrels had, by dawn, dissolved into a mere haze in my recollection.
The patrons, in a state of profound inebriation, spoke in tongues so slurred as to be incomprehensible; some were unable to lift themselves from the floor, yet somehow retained a remarkable grip on their glasses, never spilling a drop. A feat, I should think, that would baffle even the keenest of minds.
Indeed, it was a night to be remembered -- though I daresay that few in attendance are likely to recall it with any clarity.
F

View File

@ -1,6 +1,5 @@
+++ +++
title = "All posts" title = "Search All Posts"
template = "posts.html" template = "posts.html"
sort_by = "date" sort_by = "date"
generate_feed = true
+++ +++

View File

@ -0,0 +1,20 @@
+++
title = "About that Hadog stawberry special…"
date = 2024-05-29
[taxonomies]
categories = ["Culture"]
[extra]
author = "Emil Miler"
+++
OK, so I was feeling adventurous today and decided to try out the new [Hadog](https://www.hadog.cz) special strawberry burger.
<!-- more -->
Holy shit, what did I just taste? I am not even sure if it was repulsive or delicious. Who am I kidding, it was probably the former. It feels like someone took a bacon burger and soaked it in a strawberry milkshake.
If burgers were music, this would be a Frank Zappa concert on mushrooms. [It felt something like this](https://youtu.be/xxAJqvslV7M?si=6iXg_1H-0peYvT-V&t=83). Like when The Beatles started doing the psychadelic stuff.
In short; I'll get the classic Hadog burger next time.

View File

@ -0,0 +1,81 @@
+++
title = "Automatic X11 scaling with autorandr and dwm"
date = 2022-12-18
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
This is a follow-up to [my previous post](@/posts/fractional-display-scaling-on-x11/index.md) about fractional display scaling. I have done more digging and finally created a working setup for scaling my displays automatically with [autorandr](https://github.com/phillipberndt/autorandr) and [dwm](https://dwm.suckless.org/).
<!-- more -->
In the past I have been trying to figure out fractional scaling on X11 and how to get QT and GTK applications to work (somewhat) properly. This post focuses on setting up a proper way of changing scaling factors without restarting X11.
My system looks like this: Laptop with a hidpi display (which I want to scale by 150%) and a docking station with two 1080p monitors (with default scaling). When connecting my laptop to the docking station autorandr reconfigures my displays and sets correct scaling. Same thing happens on disconnect. This is all done without needing to restart the running X11 session -- though individual applications need to be restarted. Also note that mixed-dpi is not possible.
## X11 Scaling
We can scale applications by setting our desired DPI in `.Xresources`. Refer to the [previous post](@/posts/fractional-display-scaling-on-x11/index.md) for more information. Here is a quick conversion table:
| | | | | | |
|------------|-------------------|------|------|------|------|
| **Scale:** | 100% | 125% | 150% | 175% | 200% |
| **DPI:** | 96&nbsp;(default) | 120 | 144 | 168 | 192 |
Though because we want to switch DPI settings, we have to create separate files for both of our environments which we are going to load with autorandr later.
```
$ cat .Xresources.fhd
Xft.dpi: 96
Xcursor.size: 16
```
```
$ cat .Xresources.hidpi
Xft.dpi: 144
Xcursor.size: 32
```
## autorandr
This program can be installed on most distributions via your package manager. Refer to the [documentation](https://github.com/phillipberndt/autorandr#installationremoval) for more information.
Save the settings for the laptop with `autorandr --save laptop`, then reconfigure the displays for the docking station and save that again with `autorandr --save dock`. This creates configuration files for both scenarios in `~/.config/autorandr/`.
We also need a script which gets executed after autorandr runs on the event of connect or disconnect. This can be done with [hook scripts](https://github.com/phillipberndt/autorandr#hook-scripts). In our case we need `postswitch` which runs after displays are set up.
```sh
#!/bin/sh
EXTERNAL="^DP.*-8"
if $(xrandr --display :0.0 --prop | egrep -q "$EXTERNAL connected"); then
xrdb -merge ~/.Xresources.fhd
else
xrdb -merge ~/.Xresources.hidpi
fi
~/.fehbg
```
Don't forget to make it executable as well by running `chmod +x ~/.config/autorandr/postswitch`.
The script checks whether a given external display is connected. In my case the display names are `DP-2-3-8` and `DP-2-3-1-8` due to DP daisy-chain. Check your own display names with `xrandr`. If any display matching the regular expression is found, the script merges `~/.Xresources.fhd`, otherwise it merges the hidpi values.
It also runs my `~/.fehbg` script which resets desktop background image, because it gets distorted on display layout change. The script is generated automatically if you use [ranger](https://ranger.github.io/). This can, of course, be left out.
## dwm
In order do get correct scaling of dwm, mainly the statusbar, it has to be restarted, ideally without losing our session. One basic way of doing this is executing dwm trough a script with an endless loop, for instance:
```sh
while true; do
dwm >/dev/null 2>&1
done
```
This would restart dwm right after the process ends. This option, though, will reset all window tags and they all get moved to tag 1.
Better way is to apply [restoreafterrestart](https://dwm.suckless.org/patches/restoreafterrestart/) and [restartsig](https://dwm.suckless.org/patches/restartsig/) patches, which allow us to restart dwm using `kill -HUP` and to preserve window tags and layouts.
Optionally you can omit the `restartsig` patch and save/restore the session manually.

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,42 @@
+++
title = "Classic xx20 keyboard FRU list"
+++
| Language | NMB | Alps | Chicony |
|--------------------------------------------------|---------|---------|---------|
| Arabic | 45N2216 | 45N2076 | 45N2146 |
| Belgian | 45N2217 | 45N2077 | 45N2147 |
| Brazilian Portuguese | 45N2215 | 45N2075 | 45N2145 |
| Bulgarian | 45N2218 | 45N2078 | 45N2148 |
| Canadian French (058) | 45N2213 | 45N2073 | 45N2143 |
| Canadian French (Acnor) | 45N2212 | 45N2072 | 45N2142 |
| Czech | 45N2219 | 45N2079 | 45N2149 |
| Danish | 45N2220 | 45N2080 | 45N2150 |
| Dutch | 45N2230 | 45N2090 | 45N2160 |
| French | 45N2222 | 45N2082 | 45N2152 |
| German | 45N2223 | 45N2083 | 45N2153 |
| Greek (U.S. English and Greek layout) | 45N2224 | 45N2084 | 45N2154 |
| Hungarian | 45N2226 | 45N2086 | 45N2156 |
| Icelandic | 45N2227 | 45N2087 | 45N2157 |
| Israel (Hebrew) | 45N2225 | 45N2085 | 45N2155 |
| Italian | 45N2228 | 45N2088 | 45N2158 |
| Japanese | 45N2242 | 45N2102 | 45N2172 |
| Kazakhstan | 45N2229 | 45N2089 | 45N2159 |
| Korean | 45N2243 | 45N2103 | 45N2173 |
| Latin American Spanish | 45N2214 | 45N2074 | 45N2144 |
| Norwegian | 45N2231 | 45N2091 | 45N2161 |
| Polish | 45N2232 | 45N2092 | 45N2162 |
| Portuguese | 45N2233 | 45N2093 | 45N2163 |
| Russian | 45N2234 | 45N2094 | 45N2164 |
| Slovak | 45N2235 | 45N2095 | 45N2165 |
| Slovenian | 45N2236 | 45N2096 | 45N2166 |
| Swedish, Finnish | 45N2237 | 45N2097 | 45N2167 |
| Spanish | 45N2221 | 45N2081 | 45N2151 |
| Swiss | 45N2238 | 45N2098 | 45N2168 |
| Thai | 45N2245 | 45N2105 | 45N2175 |
| Traditional Chinese | 45N2244 | 45N2104 | 45N2174 |
| Turkish | 45N2239 | 45N2099 | 45N2169 |
| Turkish (F Type) | 60Y9550 | 60Y9552 | 60Y9554 |
| U.K. English | 45N2240 | 45N2100 | 45N2170 |
| U.S. English | 45N2211 | 45N2071 | 45N2141 |
| U.S. English (International, with a Euro symbol) | 45N2241 | 45N2101 | 45N2171 |

View File

@ -0,0 +1,179 @@
+++
title = "Classic keyboard mod"
date = 2019-08-25
[extra]
author = "Emil Miler"
[taxonomies]
categories = ["ThinkPad", "Hardware"]
+++
Starting with the 30 series, ThinkPads got a new modernized keyboard and many poeple dislike it. Do not take me wrong, it is not a bad keyboard, but when compared to the older model, it has a plethora of issues. Luckily, it can be replaced with the classic 10--20 series keyboard.
<!-- more -->
Interesting references:
- [My old talk about ThinkPad modding at LinuxDays in Prague](https://www.youtube.com/watch?v=60o5ZVQCPcw) (Czech)
- [My updated talk presented in 2019](https://www.youtube.com/watch?v=R_SXGbItqbI) (Czech)
## Things wrong with the new keyboard
![Keyboard comparison](comparison.jpg)
*New keyboard on the left, classic keyboard on the right.*
The main difference is that the new keyboard has very different "island" or "chicklet" keys. They are all separated from each other and form "islands", hence "island-style" keyboard. This new design has less travel distance than the old keys had.
The worst change, in my opinion, is the new layout. Look at the *Delete, Home, Pg\*, End* area on the old keyboard and compare it to the new layout. It has disappeared completely and is now a single row. I am unable to hit the correct keys when not looking at the keyboard.
Also, where are my multimedia Fn keys?! Why would Lenovo decide to move them to the F row? I guess I am just used to it and it is not really that big of a deal, but it bugs me.
Actually, several models of the new keyboard have backlight. Some people I know quite like this feature. Fun fact: the 30 series are the only ThinkPads which have both keyboard backlight and ThinkLight.
## Sourcing the keyboard
If you have an older ThinkPad (xx10 or xx20), you can take the keyboard out of that. Otherwise you will have to buy a spare. There are three classic keyboard manufacturers: NMB, Alps and Chicony.
Every keyboard has it's *FRU* -- Field Replacement Unit number -- by which you can identify any part. It can tell you which manufacturer made it and what layout it has. Here is a table of FRUs for the *US ANSI* layout:
| Manufacturer | Country | FRU |
|--------------|---------|---------|
| NMB | Japan | 45N2211 |
| Alps | Korea | 45N2070 |
| Chicony | China | 45N2141 |
You can read a [full list of all FRUs](@/posts/classic-keyboard/fru-list.md), as found in the [x220 hardware maintenance manual](https://download.lenovo.com/ibmdl/pub/pc/pccbbs/mobiles_pdf/0a60739_01.pdf) on pages 125--126 and the [Lenovo support site](http://web.archive.org/web/20191204204012/https://pcsupport.lenovo.com/hr/en/solutions/pd010629) (The official website has been taken down, so the anchor links to an archive).
### Comparing manufacturers
I have tried using keyboards from all three manufacturers and I can safely say that NMB is the best of the three. You will have to take my word for it, but this opinion is shared among many people I discussed this with, though in general, the hype is way too overblown.
Alps is just a mushy mess with no tactile feeling and poor quality. Chicony is pretty nice, but their keyboards are inconsistent and you can end up with a well-feeling piece or a crappy one. NMB has by far the best feeling, build quality and is consistent, but in my opinion, it is not worth the stupidly large price or the trouble of trying to find a nice piece. The main difference are the switches:
![Keyboard switches](switches.png)
*From top to bottom: NMB, Chicony, Alps. NMB can be easily recognized by the red rubber domes.*
### Fake keyboards
The hardest part of this whole endeavor is finding a genuine keyboard. To be honest, finding a real keyboard can be a challenge, since there have been some "fake" keyboards appearing on eBay. They may even have some weird coating which comes off after rubbing the keys.
![Fake keyboard keys](fake-keyboard.jpg)
- [Video 0](fake-keyboard-00.mp4)
- [Video 1](fake-keyboard-01.mp4)
Videos and images of the fake keyboard are from [@kirbychan](https://telegram.me/kirbychan). As he had said:
> I guess it's more of a bait, or some refurbished shit which went wrong and somehow ended up coating the keys with kensur chinks plastic.
Some fake keyboards have a really low quality switches and the printed letters are misaligned. You can tell that you have a fake keyboard by looking at the middle trackpoint button blue points, which are usually smaller on the fake.
![Comparison of fake trackpoint button](fake-comparison-button.jpg)
The trackpoint dome is also placed below the actual keys on the fake keyboard and therefore is pretty unusable.
![Comparison of fake trackpoint dome](fake-comparison-trackpoint.jpg)
List of confirmed sellers selling fakes:
- Shop3905046 (AliExpress)
- nuflower2009 (eBay)
I have no idea how to avoid these completely except buying used keyboards.
### Buying keyboards
It is pretty hard to find anything but Chicony (or a fake). Lenovo even re-branded some Chicony keyboards to *45N2211* (NMB). As far as I know, there are no new NMB keyboards and you have to buy them used and taken out of broken machines. As I have said before, it is not worth the hassle and a much more common Chicony will be fine.
If you are set on getting NMB, look for listings that do not have the generic picture as any other seller, always check the picture for the correct FRU and **Always send a message to the seller asking about the FRU**! This goes for both eBay and AliExpress.
## Isolating backlight power
If you don't want to kill your new keyboard, it is necessary to isolate pins which deliver high current to the modern keyboard backlight. Since the old keyboard does not have backlight, it will overheat and melt. If you are lucky, it will burn in a way which disconnects the pins, but usually it just destroys the cable.
![Flex cable folded](flex-folded.jpg)
Disassemble the part holding the cable in place. It is a tight fit, so be careful not to tear anything and do not lose any screws. Pull out the cable sandwich from there. It is necessary to isolate pins *25* and *29* according to a schematic found on [our favourite forum](https://forum.thinkpads.com/viewtopic.php?t=121522).
I used a piece of electrical tape and covered pins *25*, *27* and *29* -- three pins next to each other. Pin *27* is a redundant ground connection, so covering it does not hurt anything and it makes it easier to isolate the others.
![Flex cable isolated](flex-isolated.jpg)
Put it back together and tighten the assembly back. Make sure you have a good quality tape, because cheap tape tends to slide around during reassembly. Best bet would be to use a piece of kapton tape. Also make sure that you did not cover the neighbouring pins, which will cause the middle trackpoint button not to function. The same may be caused by a thick tape as well, as the pins would not get a proper connection when reassembled back
## Swapping the keyboard
There is a difference in thickness of the front mounting pins. Since the X230 and T430 have different keyboard mounting methods, this section is split for both machines respectively.
![Keyboard pins](keyboard-nubs-compared.jpg)
*Image sourced from [ThinkWiki](https://www.thinkwiki.org/wiki/File:T410keyboardnubs.jpg).*
The new and old keyboards both use the same motherboard connector, so no modification is necessary there. Be careful though when pulling the connector out of the motherboard, since the cable likes to tear! I suggest pulling it by the part shown by the green arrow, not at the red cross.
![Where to pull the cable](keyboard-cable.jpg)
### T430
The T430 has the keyboard secured in the chassis itself and the slots are made for the new keyboard, so a physical modification of the nubs is necessary in order to fit.
![Nub modification](nub-modification.jpg)
I usually take a small dremel and file them down. You will have to get rid of the nub next to the trackpoint keys completely since there is no mounting hole for it. I then paint the filed-down spots with a black permanent marker.
Be careful not to hit any keys, especially the middle trackpoint key. It has two little mounting legs which like to snap off. If you manage to screw it up, take a look at [my article about fixing it](/posts/fixing-broken-middle-trackpoint-button/index.md).
You might have read on ThinkWiki, that you can buy a palmrest from T420 and swap it in as well. **IT DOES NOT FIT!!!** Do not waste money on this. They recently fixed it on the wiki, but some people still spread this myth.
You might have also read the popular [Definitive T430 Modding Guide](https://medium.com/@n4ru/the-definitive-t430-modding-guide-3dff3f6a8e2e) where George Kushnir suggests this:
> While most guides will point you towards either taking a dremel to the nubs or replacing the palmrest, you can actually place the keyboard under the palmrest, omit the two screws next to the touchpad, and simply drop in the keyboard and palmrest assembly together for a near perfect fit.
What the fuck?! Just do it properly and avoid this shitty advice. He even mentions the non-working palmrest swap.
### X230
Unlike the T430, you will have to buy a spare X220 palmrest. The X220 and X230 palmrests can be swapped without problems. The keyboard does not mount into slots on the chassis, but instead is held only by the palmrest itself. In case you do not want to buy a new palmrest, you can cut larger holes in the X230 palmrest or file down the nubs, as you would with the T430.
You can either buy an original Lenovo palmrest with proper insulation, or you can get a Chinese clone. I must say that the clones are pretty ok, but if you want top-quality stuff, go for the better, albeit pricey, original Lenovo palmrest.
## Flashing EC firmware
Lenovo changed not only the physical layout, but the software key-map as well. Because of this, many *Fn* combos are not working properly. This can be fixed by flashing a custom EC firmware with a modified key-map. This is not BIOS flashing as many suggest.
If you would like to know more about this, watch a [talk by Hamish Coleman](https://youtube.com/watch?v=Fzmm87oVQ6c) about how he reverse-engineered the firmware and the key-map. I will not go in-depth about this here.
There are several approaches to flashing the EC firmware, such as using an external flasher and writing directly to the EEPROM. There is a simple method though -- booting a pre-made DOS-based flash tool with the modified firmware. This approach is recommended by Coleman as well.
### Creating a bootable USB stick
This is a short rewrite of the [official instructions](https://github.com/hamishcoleman/thinkpad-ec#step-by-step-instructions).
```sh
git clone https://github.com/hamishcoleman/thinkpad-ec
cd thinkpad-ec
make list_laptops
make patched.x230.img
dd if=patched.x230.img of=/dev/sdx
```
Beware, this will delete all data on the target device! If you mess up the disk names, you will rewrite a different storage device, perhaps even your system! You have been warned.
### Flashing the firmware
First make sure that you have your battery charged and that you have AC plugged in. It will refuse to flash new firmware otherwise.
Reboot your machine and select to boot from USB. My machine refuses to boot with some cheap USB sticks, so try several if you experience this.
You should boot into the DOS flashing utility. Just follow the instructions. After it does the flash and reboots, you can boot into your system again. Test the patch by trying to invoke any *Fn* combo such as *Fn+Space* to toggle the ThinkLight.
If it does not work, you probably did not have your battery or AC plugged in. I also had problems with using dock as the power source, so use a real AC adapter instead.
## Conclusion
![Finished project](finished.jpg)
There it is, a working classic keyboard on your 30 series ThinkPad. Only thing not working now is the green *CapsLock* LED. Fixing that in software is, according to Coleman, pretty complicated, if not impossible. I have a Caps indicator in my status bar, so this does not really bother me that much.
There have been some projects which tried restoring the LED by making a custom board connected to USB and controlling it via software, but they were never finished.

View File

@ -0,0 +1,192 @@
+++
title = "Replacing xx30 chicklet keyboard with the classic xx20"
date = 2019-08-26
[taxonomies]
categories = ["ThinkPad", "Hardware"]
+++
Starting with the 30 series, ThinkPads - among other things - got a new "modernized" keyboard. As You might have guessed, I do not like it. Do not take me wrong, it is not a bad keyboard, but when compared to the older model, it has a plethora of issues.
Interesting references:
- [My old talk about ThinkPad modding at LinuxDays in Prague](https://invidio.us/watch?v=60o5ZVQCPcw) (Czech)
- [My updated talk presented in 2019](#) (Czech)
---
## Things wrong with the new keyboard
![Keyboard comparison](comparison.jpg)
*New keyboard on the left, classic keyboard on the right*
The main difference is that the new keyboard has very different "island" keys, or "chicklet" as they call it. The keys are all reparated from each other and form "islands", hence "island-style" keyboard. Those new keys have less travel distance than the old keys.
The worst chnage, in my opinion, is the new layout. Look at the *Delete, Home, Pg\*, End* area on the old keyboard and compare it to the new layout. It has disappeared completely and is now a single row. I am unable to hit the correct keys whilst not looking at the keyboard.
Also, where are my multimedia Fn keys?! Why on Earth would Lenovo decide to move them to the F row?
Actually, some of the new keyboards have backlight. Few people I know quite like this feature, but I prefer the ThinkLight. Fun fact - the 30 series are the only ThinkPads which have both keyboard backlight and ThinkLight.
## Sourcing the keyboard
If you have an older ThinkPad (xx10 or xx20) you can take the keyboard out of that. Otherwise you will have to buy a spare. There are three classic keyboard manufacturers: NMB, Alps and Chicony.
Every keyboard has it's *FRU* - a serial number if you will. It tells you which manufacturer made the keyboard and what layout it has. As I only use ANSI, I go by this table:
Manufacturer|Country|FRU
-|-|-
NMB|Japan|45N2211
Alps|Korea|45N2070
Chicony|China|45N2141
For a ful llist of all FRUs refer to the [Lenovo support site](https://pcsupport.lenovo.com/hr/en/solutions/pd010629).
### Comparing manufacturers
I have tried using keyboards from all three manufacturers and I can safely say that you want to buy NMB. You will have to take my word for it, but this opinion is shared among many people I discussed this with.
Alps is just a mushy mess with no tactile feeling and poor quality. Chicony is fine, but their keyboards are inconsistent and you can end up with a well-feeling piece or a crappy one. NMB has by far the best feeling and build quality. You can even tell by looking at the keys side-by-side. The main difference are the switches:
![Keyboard switches](switches.png)
*From top to bottom: NMB, Chicony, Alps. NMB can be easily recognised by the red rubber domes.*
### Fake keyboards
There have been some "fake" keyboards appearing on eBay. They have weird coating which comes off after rubbing the keys.
![Fake keyboard keys](fake-keyboard.jpg)
- [Video 0](fake-keyboard-00.mp4)
- [Video 1](fake-keyboard-01.mp4)
Videos and images above are sourced from [@kirbychan](https://telegram.me/kirbychan). As he had said:
> I guess it's more of a bait, or some refurbished shit which went wrong and somehow ended up coating the keys with kensur chinks plastic.
Some fake keyboards have a really low quality switches and the printed letters are misaligned. You can tell that you have a fake keyboard by looking at the middle trackpoint button blue points, which are smaller on the fake.
![Comparison of fake trackpoint button](fake-comparison-button.jpg)
The trackpoint dome is also placed below the actual keys on the fake keyboard and therefore is pretty unusable.
![Comparison of fake trackpoint dome](fake-comparison-trackpoint.jpg)
List of confirmed sellers selling fakes:
- Shop3905046 (AliExpress)
- nuflower2009 (eBay)
I have no idea how to avoid these completely except buying used NMB boards.
### Buying keyboards
It is pretty hard to find anything but crappy chinese models. Lenovo even rebranded some Chicony keyboards to *45N2211* (NMB). There are no new NMB keyboards in my experience and I have to buy boards taken out of broken machines.
Look for listings that do not have the generic picture as any other seller, always check the picture for the correct FRU and **Always send a message to the seller asking about the FRU**! That is unless you want Chicony, then go for anything you find really. This goes for both eBay and AliExpress.
## Isolating backlight power
If you do not want your keyboard to start burning, it is necessary to isolate pins which deviler high current to the backlight on the modern keyboards. Since the old keyboard does not have backlight, it will overheat and it sometimes starts to melt. If you are lucky, it will burn in a way which disconnects the pins, but I am not willing to risk that.
![Flex cable folded](flex-folded.jpg)
Disassemble the part holding the cable in place. It is a tight fit, so be careful not to tear anything and do not lose any screws. Pull out the cable sandwich from there. It is necessary to isolate pins *25* and *29* according to a [shematic](#) found on [our favourite forum](https://forum.thinkpads.com/viewtopic.php?t=121522).
I used a piece of electrical tape and covered pins *25*, *27* and *29* - three pins next to each other. Pin *27* is a redundant ground connection, so covering it does not hurt anything and it makes it easier to isolate the others.
![Flex cable isolated](flex-isolated.jpg)
Put it back together and tighten the asembly back. Make sure you have a good quality tape, because cheap tape tends to slide around during reassembly. Also make sure that you did not cover the neighbouring pins, which will cause the middle trackpoint button not to function. The same may be caused by a thick tape as well.
## Swaping the keyboard
There is a difference in thickness of the front mounting pins. Since the X230 and T430 have different keyboard mounting methods, this section is split for both machines respectively.
![Keyboard pins](keyboard-nubs-compared.jpg)
*Image sourced from [ThinkWiki](https://www.thinkwiki.org/wiki/File:T410keyboardnubs.jpg)*
The new and old keyboards both use the same motherboard connector, so no modification is necessary there. Be careful though when pulling the connector out of the motherboard - The cable likes to tear! I suggest pulling it by the part shown by the green arrow, not at the red cross.
![Where to pull the cable](keyboard-cable.jpg)
### T430
The T430 has the keyboard secured in the chasis itself and the slots are made for the new keyboard, so a physical modification of the nubs is necessary in order to fit.
![Nub modification](nub-modification.jpg)
I usually take a small dremel and file them down. You will have to get rid of the nub next to the trackpoint keys completely since there is no mounting hole for it. I then paint the filed-down spots with a black permanent marker.
Be careful not to hit any keys, especially the middle trackpoint key. It has two little mounting legs which like to snap off. If you manage to screw it up, take a look at [my article about fixing it](#) (yes, I screwed it up).
You might have read on ThinkWiki that you can buy a palmrest from T420 and swap it in as well. **IT DOES NOT FIT!!!** Do not waste money on this. They recently fixed it on the wiki, but some people still spread this myth.
You might have also read the [Definitive T430 Modding Guide](https://medium.com/@n4ru/the-definitive-t430-modding-guide-3dff3f6a8e2e) where George Kushnir suggests this:
> While most guides will point you towards either taking a dremel to the nubs or replacing the palmrest, you can actually place the keyboard under the palmrest, omit the two screws next to the touchpad, and simply drop in the keyboard and palmrest assembly together for a near perfect fit.
What the fuck?! Just do it properly and avoid this shitty advice. He even mentions the palmrest swap.
### X230
Unlike the T430, you will have to buy a spare palmrest for X220. These two can be swapped and are necessary for a perfect fit. The keyboard does not mount into slots on the chasis, but instead is held only by the palmrest. In case you do not want to buy a new palmrest, you can cut larger holes in the X230 palmrest or file down the nubs as if you would with the T430.
You can either buy an original Lenovo palmrest with propper isolation and other things or you can buy a chinese clone. I must say that the chinese did a nice job with these, but if you want quality, go for the better albeit pricey original.
## Flashing EC firmware
Lenovo changed not only the physical layout, but the software keymap as well. Thanks to this many *Fn* combos are not working properly. This can be fixed by flashing a custom EC firmware with a modified keymap. This is not BIOS flashing as many suggest.
If you would like to know more about this, watch a [talk by Hamish Coleman](https://invidio.us/watch?v=Fzmm87oVQ6c) about how he reverse-engineered the firmware and the keymap. I will not go in-depth about this here.
There are several approaches to flashing the EC firmware, such as using an external flasher and writing directly to the EEPROM. There is a simple method though - booting a premade DOS-based flash tool with the modified firmware. This approach is reccomended by Coleman as well.
### Creating a bootable USB stick
This guide is a rewrite of the [official instructions](://github.com/hamishcoleman/thinkpad-ec#step-by-step-instructions).
Install required libraries.
`emerge -av ...`
Clone the source code.
`git clone https://github.com/hamishcoleman/thinkpad-ec`
Chnage the working directory to the cloned repository.
`cd thinkpad-ec`
Show the list of laptops and USB image file names.
`make list_laptops`
Choose your laptop model from the list, eg. *patched.x230.img* for the X230 and build the patched image.
`make patched.x230.img`
Insert your USB flash drive and determine it's name in the system.
`lsblk -d`
Write the patched image to your flash drive. **This will erase everything on the storage device!**
`dd if=patched.x230.img of=/dev/sdx`
If you mess up the disk names, you will rewrite a different storage device, perhaps even your system! You have been warned.
### Flashing the firmware
First make sure that you have your battery charged and that you have AC pluged in. It will refuse to flash new firmware otherwise.
Reboot your machine and select to boot from USB. My machine refuses to boot with some cheap USB sticks, so try several if you experience this.
You should boot into the DOS flashing utility. just follow the instructions. After it does the flash and reboots, you can boot into your system again. Test the patch by trying to invoke any *Fn* combo such as *Fn+Space* to toggle the ThinkLight.
## Conclusion
![Finished project](finished.jpg)
There you have it, a working classic keyboard on your 30 series ThinkPad. Only thing not working now is the green *CapsLock* LED. Fixing that in software is, according to Coleman, pretty complicated, if not impossible. I have a Caps indicator in my statusbar, so this does not really bother me that much. I will perhaps write about a hardware hack on how to get this working, so stand-by for updates.

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

View File

@ -0,0 +1,68 @@
+++
title = "Connecting Kodi to Nginx media index"
date = 2022-10-19
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Connecting Kodi to network media storage can be cumbersome to setup, especially with NFS. This setup uses simple HTTP and Nginx instead.
<!-- more -->
Assuming that Kodi is installed and connected to our network and we have a server with Nginx. We just need to expose our media storage with auto-indexing enabled. This might seem insecure, but we are only exposing things to our internal trusted network. Never let any untrusted devices into your subnet -- which should go without saying.
## Nginx
I am using Nginx as a reverse proxy to other services and media directories, so I have to deal with different locations. Simple configuration could look like this.
```
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server.local 192.168.1.10;
root /srv/www/default;
index index.html;
charset UTF-8;
location / {
try_files $uri $uri/ =404;
}
location /films {
alias /srv/media/films;
autoindex on;
}
location /shows {
alias /srv/media/shows;
autoindex on;
}
}
```
Make sure to set `charset UTF-8;` to enable special characters. I use both mDNS *server.local* and IP address for VPN access and because Alpine clients do not support mDNS address resolution due to musl limitations.
After reloading Nginx, the file index should be available at both:
- `http://server.local/films`
- `http://192.168.1.10/films`
## Kodi
We can now add a new share in Kodi and select a custom network location, which lets us choose from many different protocols.
![](kodi-browse-for-new-share.png)
Simply select HTTP, set your server address and set the remote path to the desired endpoint. The address can be the mDNS hostname, if your client supports address resolution.
![](kodi-add-network-location.png)
## Conclusion
That's it, extremely simple and read-only media share. I recommend managing your library with something that can generate `movie.nfo` for each film -- for example [Radarr](https://radarr.video/) -- and turn off metadata fetching from the Internet. Parsing files and other metadata -- including images -- will be quite snappy.

View File

@ -0,0 +1,68 @@
+++
title = "Connecting Kodi to Nginx media index"
date = 2022-10-19
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Connecting Kodi to netowrk media storage can be very cumbersome to setup, especially with NFS. This setup uses simple HTTP and Nginx instead.
<!-- more -->
Assuming that Kodi is installed and connected to our network and we have a server with Nginx. We just need to expose our media storage with autoindexing enabled. This might seem insecure, but we are only exposing things to our internal trusted network. Never let any untrusted devices into your subnet -- which should go without saying.
## Nginx
I am using Nginx as a reverse proxy to other services and media directories, so I have to deal with different locations. Simple configuration could look like this.
```
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name server.local 192.168.1.10;
root /srv/www/default;
index index.html;
charset UTF-8;
location / {
try_files $uri $uri/ =404;
}
location /films {
alias /srv/media/films;
autoindex on;
}
location /shows {
alias /srv/media/shows;
autoindex on;
}
}
```
Make sure to set `charset UTF-8;` to enable special characters. I use both mDNS *server.local* and IP address for VPN access and because Alpine clients do not support mDNS address resolution due to musl limitations.
After reloading Nginx, the file index should be available at both:
- `http://server.local/films`
- `http://192.168.1.10/films`
## Kodi
We can now add a new share in Kodi and select a custom network location, which lets us choose from many different protocols.
![](kodi-add-network-location.png)
Simply select HTTP, set your server address and set the remote path to the desired endpoint. The address can be the mDNS hostname, if your client supports address resolution.
![](kodi-network-location.png)
## Conclusion
That's it, extremely simple and read-only media share. I recommend managing your library with something that can generate `movie.nfo` for each film -- for example [Radarr](https://radarr.video/) -- and turn off metadata fetching from the Internet. Parsing files and other metadata -- including images -- will be very snappy.

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,39 @@
+++
title = "Fixing middle trackpoint button"
date = 2019-08-26
[extra]
author = "Emil Miler"
[taxonomies]
categories = ["Hardware", "ThinkPad"]
+++
You might have attempted to [replace the keyboard on your T430](@/posts/classic-keyboard/index.md) and you broke the middle trackpoint button. Well, here is how to fix it.
<!-- more -->
## The problem of the middle button
Despite all the engineering old ThinkPads went trough, the xx20 series keyboards have a crappy middle thrackpoint button. It is pivoting around two long plastic hinges with a very tiny diameter. Those hinges like to snap when the key is being pushed the wrong way or is removed incorrectly.
## Buying a replacement key
Well, this option is there, but who would want to spend insane amount of money on a single key?
If you do decide to go this route, be aware that there are [several manufacturers of the keyboard](@/posts/classic-keyboard/index.md#comparing-manufacturers) and they all have slightly different keys.
## Fixing the problem
I have tried several ways of fixing the key, including 3D printing a replacement hinges and gluing them. I even tried printing the full key altogether. None of these methods worked well though, as printing such a small part is pretty difficult on a typical FDM printer. I guess you could do it with an SLA printer though.
I ended up replacing the hinges with metal. Yes, parts made of metal and plastic rubbing each other do not lead to good results in the long-run, but this one works well.
![Comparison of original and fixed buttons](comparison.jpg)
*Button on the left is original (albeit from an xx30 keyboard) and button on the right is the one I fixed.*
I ~~borrowed~~ stole some sewing needles from my girlfriend, heated them up on open flame and inserted them into the nubs from where the hinges used to protrude. It melted the plastic and created a hole for itself and it stayed in place after cooling down. I then shortened the needles with simple pliers and the hinges were back!
Sometimes, when fixing other hinges, the needle would not stay in place and would move about. A quick solution is to put a small dab of hot glue on it and the problem is fixed.
Interestingly, this solution is working years after it's conception to this very day. ~~I use the machine daily~~ and it still holds up, although I do not dare to take the key out to inspect how it's doing. I will likely replace the whole keyboard before it breaks completely.

View File

@ -0,0 +1,34 @@
+++
title = "Fixing broken trackpoint middle button"
date = 2019-08-25
[taxonomies]
categories = ["ThinkPad"]
+++
You might have attempted to [replace the keyboard on your T430](@/thinkpad-classic-keyboard/index.md). You might have also happened to break the middle trackpoint button whilst getting rid of the nubs. Well, I have something to tell you - I did that as well. Here is how to fix it.
---
## The problem of the middle button
Despite all the engineering old thinkpads went trough, the xx20 series keyboards have a flaw in the middle thrackpoint button. It is pivoting around two long hinges with a very tiny diameter. Those hinges like to snap when the key is being pushed the wrong way or is removed incorrectly.
## Buying a replacement key
Well, this option is there, but who would want to spend insane amount of money on a single key?
If you do decide to go this route, be aware that there are [several manufacturers of the keyboard](@/thinkpad-classic-keyboard/index.md#comparing-manufacturers) and they all have slightly different keys.
## Fixing the problem my own way
I have tried several ways of fixing the key, including 3D printing a replacement hinges part i would stick on using glue. I even tried printing the full key altogether. None of these methods worked well though, as printing such a small part is pretty difficult.
I ended up replacing the hinges with metal. Yes, parts made of metal and plastic rubbing each other do not lead to good results in the long-run, but I had no choice.
![Comparison of original and fixed buttons](comparison.jpg)
*Button on the left is original (albeit from xx30 keyboard) and button on the right is the one I fixed.*
I took (stole) some sewing needles from my girlfriend, heated them up on open flame and inserted them into the nubs from where the hinges used to protrude. It melted the plastic and created a hole for itself and it stayed in place after cooling down. I then shortened the needles with simple pliers and the hinges were back!
Interestingly, this solution is working years after it's conception to this very day. I use the machine daily and it still holds up, although I do not dare to take the key out to inspect how it's doing. I will likely replace the whole keyboard before it breaks completely.

View File

@ -0,0 +1,139 @@
+++
title = "Fractional display scaling on X11"
date = 2021-12-27
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
X11 supports fractional scaling perfectly well, but most GUI toolkits don't implement it properly. Scaling works fine in a pure QT environment, but when using other GUI toolkits (such as GTK+), things don't work as expected due to them being poorly written. This article describes several methods of universal mixed display scaling with broken GUI toolkits and a simple window manager (dwm).
<!-- more -->
A huge chunk of this article is inspired by William Storey and Rico Sta. Cruz (see [Resources](#resources)).
## How scaling works
There is a more detailed explaination written by Giuseppe Bilotta in [his article](http://wok.oblomov.eu/tecnologia/mixed-dpi-x11/).
In short: Scaling support has to be implemented properly by the application, or subsequently the GUI toolkit. Most toolkits and applications are broken and fractional scaling has to be hacked together to be universal.
There are several ways to set UI scaling and each works for different things. They need to be combined to affect *most* of the system and they can either affect font size or UI elements, such as margins, paddings, etc. The intended X11 way is setting `Xft.dpi` in `.Xresources`. Some toolkits do not support this and instead use custom environment variables.
### Calculating DPI
The DPI can either be calculated or obtained for a display datasheet. Scaled DPI can be calculated by subtracting n% to get the desired value. For instance, my display has 277 DPI and my desired scaling is 150%.
```
277 - 50% = 138.5
```
Even though any scaling value can be set, it is best to select one of the following values closest to the calculation result. The reason for this is that arbitrary fractions may result in broken bitmap scaling.
| | | | | | |
|------------|--------------|------|------|------|------|
| **Scale:** | 100% | 125% | 150% | 175% | 200% |
| **DPI:** | 96 (default) | 120 | 144 | 168 | 192 |
In my particular case, the most optimal DPI value would be 144.
## Simple UI scaling
| | |
|-----------------------------|----------------------|
| Multiple mixed-DPI monitors | No |
| Requires xserver restart | Yes |
| Performance | Fast |
| Image Quality | Good |
This allows us to scale the UI by any factor, but it will not work with mixed-DPI monitors. Switching to different scaling also requires an xserver restart, or restarting all individual applications.
More information about different toolkits can be found at [Archlinux Wiki](https://wiki.archlinux.org/title/HiDPI#GUI_toolkits).
### Xft.dpi
Global xrandr configuration for UI scaling is set in `.Xresources` by setting `Xft.dpi` to the desired value, eg.
```
Xft.dpi: 144
```
### QT
QT scaling on legacy applications can be enabled by exporting `QT_AUTO_SCREEN_SCALE_FACTOR=1`.
In case the core protocol does not report our primary monitor DPI correctly, we have to set the DPI manually, eg. in our `.profile` or `.bash_profile`.
```
export QT_AUTO_SCREEN_SCALE_FACTOR=0
export QT_SCALE_FACTOR=1.5
export QT_FONT_DPI=96
```
`QT_AUTO_SCREEN_SCALE_FACTOR=0` disables the automatic scaling, as some applications with forces dcaling would get scaled twice. `QT_SCALE_FACTOR=1.5` sets the desired scale factor (150%). Since we have set xrdb DPI to support other toolkits, this alo will result in huge fonts, so they need to be reset back to default by `QT_FONT_DPI=96`. This should result in good-looking QT scaling.
### GDK3
Since we are using a simple window manager, the `Xft.dpi` setting should scale everything properly.
In case your icons don't scale well, you can force GDK scaling with `GDK_SCALE` and `GDK_DPI_SCALE`.
```
export GDK_SCALE=2
export GDK_DPI_SCALE=0.5
```
This would scale everything up by the factor of 2 (it only accepts an integer) and scale fonts back down by 50%. Despite fonts being scaled properly, the resulting margins/paddings and icons are larger, since they get scaled by 200%, not 150%.
## Mixed monitors with different DPI
| | |
|-----------------------------|--------------------------|
| Multiple mixed-DPI monitors | Yes |
| Requires xserver restart | No |
| Performance | Poor |
| Image Quality | Poor on low-DPI displays |
In case you want multiple monitors with mixed DPI, this method has to be used. Despite working as intended, the downscaling results in a poorer image quality on low-DPI displays. Large scaling factors may also result in poor performance. In my case, browser lag while scolling was very noticeable.
First step is to scale the UI by 200%, similar to the previous step.
Add the following to `.Xresources`:
```
Xft.dpi: 192
```
and to `.bash_profile`:
```
export GDK_SCALE=2
export GDK_DPI_SCALE=0.5
export QT_AUTO_SCREEN_SCALE_FACTOR=0
export QT_SCALE_FACTOR=2
export QT_FONT_DPI=96
```
Next step is to configure downscaling in xrandr by a specific factor for each monitor.
```
...todo...
```
Changing the scaling factor can be done simply by running xrandr again with chosen scaling factor and everything works as it should.
Citing Giuseppe Bilotta:
>If you think this idea is a bit stupid, shed a tear for the future of the display servers: this same mechanism is essentially how Wayland compositors -- Wayland being the purported future replacement for X -- cope with mixed-DPI setups.
## Resources
- <https://ricostacruz.com/til/fractional-scaling-on-xorg-linux>
- <https://wiki.archlinux.org/title/HiDPI>
- <https://blog.summercat.com/configuring-mixed-dpi-monitors-with-xrandr.html>
- <https://github.com/burntcustard/x11-fractional-display-scaling>
- <http://wok.oblomov.eu/tecnologia/mixed-dpi-x11/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

View File

@ -0,0 +1,72 @@
+++
title = "Hacking a smart Philips lightbulb"
date = 2021-12-29
[taxonomies]
categories = ["Hardware", "IoT"]
[extra]
author = "Emil Miler"
+++
I got my hands on a Xiaomi Philips smart LED lightbulb (ESP8266) and my goal was to hack it, install custom firmware and effectively get rid of the Xiaomi botnet.
<!-- more -->
## Hardware & disassembly
The bulb has a fixed colour temperature of 2700K, uses 9W and outputs up to 806lm. It is built on *ESP8266*, precisely [esp-wroom-02d](https://www.espressif.com/sites/default/files/documentation/esp-wroom-02u_esp-wroom-02d_datasheet_en.pdf). This means that installing custom ESP-compatible firmware is possible -- for instance [Tasmota](https://tasmota.github.io/docs/). The rest is just a simple power supply and LED array.
![](led-array.jpg)
There are several versions of this lighbulb and I could not find anything about this particular version. The main differences seem to be the entire PCB and housing. Most of the older versions are accessible without much force.
I started by popping off the light diffuser. This takes just a bit of prying, since it is lightly glued to the base. After taking out two screws, the LED array can be unplugged and taken out of the assembly. This leaves the ESP antenna exposed, but the rest of the board is still inaccessible.
There is no way of getting into this particular model without a bit of cutting. I took my dremmel and cut out part of the almuninum casing/heatsink to get to the PCB. This made the important part of the board accessible and exposed all the relevant pins.
![](pins.jpg)
## Accessing UART
In order to be able to communicate with the device, we need to connect *RX* and *TX* pins, *3.3V* and *GND*. We also need access to the *IO0* pin used for enabling the UART download mode.
![](esp-wroom-02.png)
I soldered wires to the relevant pins and connected them to my USB-TTL programmer. Don't forget that *RX* and *TX* should be crossed, so *RX* on the ESP should lead to *TX* on the programmer.
![](soldering.jpg)
To access the UART download mode, the chip has to have *IO0* pulled to ground during boot. This can be done simply by shorting the pin to ground.
## Building and flashing Tasmota
I used PlatformIO for the firmware compilation and flashing. You have to be a member of the `dialout` group in order to be able to access the device.
```sh
git clone https://github.com/arendst/tasmota/
cd tasmota
platformio run -e tasmota --target upload --upload-port /dev/ttyUSB0
```
After configuring basic network access, the firmware has to be set to *generic* and *GPIO15* to *PWM1*. Here is a configuration template:
```
{"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,0,0,0,37,0],"FLAG":0,"BASE":18}
```
## Troubleshooting
I got suck for a long while at a problem where the ESP refused to respond or was sending invalid data. My first thought was to make both data wires shorter and set lower baudrate to eliminate noise, which did not help. I then tried to supply external power, as recommended in the [official troubleshooting documentation](https://docs.espressif.com/projects/esptool/en/latest/esp32/troubleshooting.html), without much luck.
It turned out to be caused by the programmer itself. The first programmer I used had a `Prolific PL-2303HX` chip. The communication started working after using a different programmer with an `FTDI` chip and modifying it to output 3.3V instead of 5V. That can be done by simply cutting the default short between *5V* and the middle pin and creating a solder jumper from *3V* instead.
![](programmer.jpg)
## References
- <https://tasmota.github.io/docs/PlatformIO-CLI/>
- <https://templates.blakadder.com/xiaomi_philips_MUE4088RT.html>
- <https://github.com/arendst/Tasmota/issues/3055/>
- <https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/boot-mode-selection.html>
- <https://docs.espressif.com/projects/esptool/en/latest/esp32/troubleshooting.html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -0,0 +1,36 @@
+++
title = "How we hacked the school voice announcement system"
date = 2022-04-19
draft = false
[taxonomies]
categories = ["Hardware"]
[extra]
author = "Emil Miler"
+++
Me and some of my students have been spending free time in one of our classrooms, as we usually do, and we started thinking about hacking the ancient school voice announcement system -- injecting a custom signal and playing our own audio throughout the whole building.
<!-- more -->
## System analysis
Our first thought was to analyze how the system works. It is an old analog network of speakers connected to a common BUS. The audio signal is sent to the shared BUS from the principals office via an amplifier. Each of the speakers has a step-down transformer (100V 1.5--3--6W) which brings the voltage down to a safe level for the 4 Ohm 8W speaker. Specifications on the speaker assembly indicate, that the system uses 100 Volts, though that probably is just the peak voltage when the amp output is very strong. The system is otherwise free of any persistent voltage.
![](schematic.png)
The goal was to somehow inject our own amplified signal trough one of the paralel speaker branches, which should -- in theory -- propagate trough the entire network. If a strong enough amplifier is used, its output can be connected to the transformer (to the speaker side) and it then gets transformed up and travels trough the BUS as if it were sent by the main amp.
## Injection prototype
We used old speakers with a small integrated amplifier, which was redirected from the embedded speakers directly to a CINCH (RCA) connector. The opposite side of the connector served as an injection vector.
I connected my phone and started playing a low-volume ~17000 Hz tone using a [Signal Generator](https://f-droid.org/en/packages/org.billthefarmer.siggen/), which -- we hoped -- none of the staff would hear, but we would. As it turned out, our theory was right and the sound could be heard coming from all of the speakers around the entire school.
Since we were at it, our plans included a persistent backdoor, which we could use to play any sounds remotely. The idea was to use a RaspberryPi with a USB sound card connected to our amplifier. The RPi would be accessible via SSH and any audio could be played wither from local storage, or streamed. This injection could also be planted to any client on the BUS.
## Conclusion
We obviously did not finish the persistent backdoor, nor did we ever play anything else besides few more low-profile tests. It was fun to analyse the system and test our theories and we certainly did learn a lot, but further poking would only cause trouble. I feel as though my students found a new passion in hacking and systems security, not only in the virtual world.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -0,0 +1,31 @@
+++
title = "Taking screenshots on Wayland with Grim and Slurp"
date = 2024-01-18
draft = false
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
I have done some experimenting with [dwl](https://codeberg.org/dwl/dwl) and [river](https://isaacfreund.com/software/river/) on Wayland, which requires a change of my X11 setup. This article quickly explains how to replace the old [Shotgun and Slop](@/posts/taking-screenshots-with-shotgun-and-slop/index.md) for a simple Wayland alternative.
<!-- more -->
This replacement is very similar to the original combo. What you need is `grim` for screenshots, `slurp` for area selection and `wl-clipboard` for clipboard features:
```sh
grim -g "$(slurp -d)" - | tee /home/$USER/scrot/$(date +'%F_%T').png | wl-copy
```
The `-d` option in `slurp` just shows us the selection dimensions, which is a neat feature.
We can also implement a simple color picker, which will grab selected pixel color and copy a hex color output to the clipboard:
```sh
grim -g "$(slurp -p)" -t ppm - | convert - -format '%[pixel:p{0,0}]' txt:- | grep -o '#[0-9A-F]\{6\}' | tr -d '\n' | wl-copy
```
More interesting ways of using Grim can be found at [Grim examples](https://sr.ht/~emersion/grim/#example-usage).

View File

@ -0,0 +1,25 @@
+++
title = "Taking screenshots on Wayland with Grim and Slurp"
date = 2023-01-18
draft = false
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
I have done some experimenting with dwl on Wayland, which requires a change of my x11 setup. This article quickly expalins how to replace the old [Shotgun and Slop](@/posts/taking-screenshots-with-shotgun-and-slop/index.md) for a simple Wayland alternative.
<!-- more -->
This replacement is very similar to the original combo. What you need is `grim` for screenshots, `slurp` for area selection and `wl-clipboard` for clipboard features.
```sh
grim -g "$(slurp -d)" - | tee /home/$USER/scrot/$(date +'%F_%T').png | wl-copy
```
The `-d` option in `slurp` just shows us the selection dimensions, which is a neat feature.
More interesting examples, such as a simple color picker, can me found at [Grim examples](https://sr.ht/~emersion/grim/#example-usage).

View File

@ -0,0 +1,25 @@
+++
title = "Taking screenshots with shotgun and slop"
date = 2022-03-10
draft = false
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
I have been having problems with *scrot* and its `-c` option for selecting a part of the screen. It glitched most of the time and rendered selection borders in the screenshot itself. I have decided to switch to something new -- [shotgun](https://github.com/neXromancers/shotgun).
<!-- more -->
There were basically two options, shotgun and [maim](https://github.com/naelstrof/maim), though shotgun seemed as a lighter and more simple alternative. It does not support many features which need to be substituted by other programs -- the unix way of doing things.
Several programs are needed: obviously shotgun, slop, tee and xclip.
```sh
shotgun $(slop -f '-i %i -g %g') - | tee /home/$USER/scrot/$(date +'%F_%T').png | xclip -t 'image/png' -selection c
```
This is my final command and works as follows. First thing that runs is `slop -f '-i %i -g %g'`, which returns the selection position and size. This gets passed to `shotgun` and is passed to `tee`. The file gets saved to my screenshot folder with the filename containing date and time generated by `date +'%F_%T'`. The binary data is also passed to xclip and copied to clipboard for quick pasting.

View File

@ -0,0 +1,97 @@
+++
title = "Transcoding your music library with acxi"
date = 2022-09-27
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
updates = [
{date = "2022-12-03", description = "Updated Pacman PKGBUILD to version 3.5.05"}
]
+++
Managing a music library is easy with tools such as [Picard](https://picard.musicbrainz.org/) from MusicBrainz, but here is how I transcode and sync my FLAC library by using [acxi](https://github.com/smxi/acxi), a powerful audio processing tool.
<!-- more -->
It works similarly to Rsync by cloning data from one place to another, but acxi can also transcode files to other formats in the process. This is great for, say, converting a FLAC library to Opus, because storing FLAC files in a phone is just insane. Having most of my music in FLAC is perfect because of no loss in quality from transcoding to lossy formats. Audiophiles begone!
## Installation
Acxi is written in Perl, so a working Perl runtime is needed. Installation can be done either from a repository, if your distribution provides a package, or downloading the script from GitHub directly.
```sh
wget -O /usr/local/bin/acxi https://github.com/smxi/acxi/raw/stable/acxi
wget -O /usr/local/share/man/man1/acxi.1 https://github.com/smxi/acxi/raw/stable/acxi.1
chmod +x /usr/local/bin/acxi
```
The output paths are important, if you later want to use the `-U` option for self-update, for which you also need *curl*.
Acxi can also do transcoding in parallel based on the number of threads you have. This functionality needs `perl-parallel-forkmanager`. If we want to do transcoding from FLAC to Opus, we need `opus-tools` as well.
### Pacman PKGBUILD
I have written a simple PKGBUILD for Pacman. There are some problems with publishing it on AUR. Also bear in mind, the following was written at the time of publishing this article and is now out-of-date.
```
pkgname=acxi
pkgver=3.5.05
pkgrel=1
pkgdesc='Audio conversion tool that helps sync lossless to lossy formats'
arch=('any')
url='https://github.com/smxi/acxi'
license=('GPL3')
depends=('perl')
optdepends=('perl-parallel-forkmanager: Parallel processing (FORK)'
'ffmpeg: FLAC resampling'
'lame: MP3 encoding'
'flac: MP3 encoding'
'vorbis-tools: Ogg encoding'
'opus-tools: Opus encoding'
'shorten: SHN to FLAC conversion'
'ffmpeg: SHN to FLAC conversion')
options=('zipman')
source=("https://github.com/smxi/acxi/archive/refs/tags/${pkgver}.tar.gz")
sha256sums=('146ff26e2f7fc4671d83acb0d68f3066777ec65cbd7b8bf812960fe5cba7ec37')
package() {
cd "$srcdir/acxi-$pkgver"
install -D -m755 "acxi" "${pkgdir}/usr/bin/acxi"
install -D -m644 "acxi.1" "${pkgdir}/usr/share/man/man1/acxi.1"
}
```
## Configuration
Acxi reads a config file during every execution in this order:
```sh
$XDG_CONFIG_HOME/acxi.conf > $HOME/.conf/acxi.conf > $HOME/.acxi.conf
```
We can create a file `~/.config/acxi.conf` and set some basic configuration options.
```sh
SOURCE_DIRECTORY=/home/em/nfs/share/music
DESTINATION_DIRECTORY=/home/em/music
INPUT_TYPE=flac
OUTPUT_TYPE=opus
COPY_TYPES=mp3
FORK=12
```
This tells acxi to convert FLAC to Opus and directly copy all MP3 files. [Some obscure albums](https://morcatanauteku.cz/) were never released in FLAC. In my case, the source directory is a NFS mount point from my file-server and transcoded files are stored locally on my laptop. The `FORK=12` option creates 12 parallel processes for transcoding, which should ideally match your thread count.
Executing `acxi` would then transcode and copy all files not present in the destination directory.
## Issues with opus-tools
There are some FLAC files which cause problems during transcoding. If that happens to you, try building opus-tools from source. See more at <https://github.com/xiph/opus-tools/issues/66>
## References
- [smxi.org](https://smxi.org/)
- [github.com/smxi/acxi](https://github.com/smxi/acxi)

View File

@ -0,0 +1,94 @@
+++
title = "Transcoding your music library with acxi"
date = 2022-09-27
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Managing a music library is easy with tools such as [Picard](https://picard.musicbrainz.org/) from MusicBrainz, but here is how I transcode and sync my FLAC library by using [acxi](https://github.com/smxi/acxi), a powerful audio processing tool.
<!-- more -->
It works similarly to Rsync by cloning data from one place to another, but acxi can also transcode files to other formats in the process. This is great for, say, converting a FLAC library to Opus, because storing FLAC files in a phone is just insane. Having most of my music in FLAC is perfect because of no loss in quality from transcoding to lossy formats. Audiophiles begone!
## Installation
Acxi is written in Perl, so a working Perl runtime is needed. Installation can be done either from a repository, if your distribution provides a package, or downloading the script from GitHub directly.
```
wget -O /usr/local/bin/acxi https://github.com/smxi/acxi/raw/stable/acxi
wget -O /usr/local/share/man/man1/acxi.1 https://github.com/smxi/acxi/raw/stable/acxi.1
chmod +x /usr/local/bin/acxi
```
The output paths are important, if you later want to use the `-U` option for self-update, for which you also need *curl*.
Acxi can also do transcoding in parallel based on the number of threads you have. This functionality needs `perl-parallel-forkmanager`. If we want to do transcoding from FLAC to Opus, we need `opus-tools` as well.
### Pacman PKGBUILD
I have written a simple PKGBUILD for Pacman. There are some problems with publishing it on AUR for now. You might be able to find my package there in the future, in which case this post will be updated.
```
pkgname=acxi
pkgver=3.5.02
pkgrel=1
pkgdesc='Audio conversion tool that helps sync lossless to lossy formats'
arch=('any')
url='https://github.com/smxi/acxi'
license=('GPL3')
depends=('perl')
optdepends=('perl-parallel-forkmanager: Parallel processing (FORK)'
'ffmpeg: FLAC resampling'
'lame: MP3 encoding'
'flac: MP3 encoding'
'vorbis-tools: Ogg encoding'
'opus-tools: Opus encoding'
'shorten: SHN to FLAC conversion'
'ffmpeg: SHN to FLAC conversion')
options=('zipman')
source=("https://github.com/smxi/acxi/archive/refs/tags/${pkgver}.tar.gz")
sha256sums=('19553ee95420b54ec0fc455daab59fe1b342b7b048877044f777dcfeb96ff4ea')
package() {
cd "$srcdir/acxi-$pkgver"
install -D -m755 "acxi" "${pkgdir}/usr/bin/acxi"
install -D -m644 "acxi.1" "${pkgdir}/usr/share/man/man1/acxi.1"
}
```
## Configuration
Acxi reads a config file during every execution in this order:
```
$XDG_CONFIG_HOME/acxi.conf > $HOME/.conf/acxi.conf > $HOME/.acxi.conf
```
We can create a file `~/.config/acxi.conf` and set some basic configuration options.
```
SOURCE_DIRECTORY=/home/em/nfs/share/music
DESTINATION_DIRECTORY=/home/em/music
INPUT_TYPE=flac
OUTPUT_TYPE=opus
COPY_TYPES=mp3
FORK=12
```
This tells acxi to convert FLAC to Opus and directly copy all MP3 files. [Some obscure albums](https://morcatanauteku.cz/) were never released in FLAC. In my case, the source directory is a NFS mount point from my file-server and transcoded files are stored locally on my laptop. The `FORK=12` option creates 12 parallel processes for stranscoding, which should ideally match your thread count.
Executing `acxi` would then transcode all files not present in the destination directory.
## Issues with opus-tools
There are some FLAC files which cause problems during transcoding. If that happens to you, try building opus-tools from source. See more at <https://github.com/xiph/opus-tools/issues/66>
## References
- [smxi.org](https://smxi.org/)
- [github.com/smxi/acxi](https://github.com/smxi/acxi)

View File

@ -0,0 +1,94 @@
+++
title = "Zola deployment with Gitea Actions and Rsync"
date = 2024-01-19
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Gitea now has a native support for Actions, which is a clone of GitHub Actions with the same syntax. Since Drone CI -- which was the topic of an older article -- seems to get slowly abandoned by upstream and Gitea Actions are now stable, it is a good idea to switch.
<!-- more -->
This article shares a lot of similarities with the [old Drone CI post](@/posts/zola-website-deployment-with-drone-ci/index.md).
The main advantage of Gitea Actions is a native integration to the Gitea UI. Al we need to do is prepare an [Act Runner](https://docs.gitea.com/usage/actions/act-runner). Compatibility with the more widely used GitHub Actions is also nice.
## Pipeline
The Act Runner reads the private key from a secret and uses it for SSH authentication. I am deliberately not using some random external modules for Rsync, since it is more trustworthy to execute your own code. The ssh-agent is necessary for a successful auth.
Zola is also installed by pulling a built release tar and extracting the binary. I have tried using the official Zola container, but it just would not work properly.
```yaml
name: Build
on:
push:
branches:
- master
env:
ZOLA_VERSION: "0.18.0"
HOST: ${{ secrets.SSH_HOSTNAME }}
HOST_DIR: ${{ secrets.SSH_TARGET_DIR }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Zola
run: |
wget https://github.com/getzola/zola/releases/download/v${ZOLA_VERSION}/zola-v${ZOLA_VERSION}-x86_64-unknown-linux-gnu.tar.gz
tar -xvzf *.tar.gz
- name: Build
run: ./zola build
- name: Deploy
run: |
apt update -y && apt-get install -y --no-install-recommends rsync
eval "$(ssh-agent -s)"
ssh-add - <<< "${SSH_PRIVATE_KEY}"
mkdir -p ~/.ssh/
ssh-keyscan -H ${HOST} >> ~/.ssh/known_hosts
rsync -r --delete-after public/* "${SSH_USERNAME}@${HOST}:${HOST_DIR}"
```
## Webserver configuration
The server needs a new user with write access to the website root directory. I still call it drone for the sake of not having to redo my server configuration.
```sh
useradd drone
mkdir -p /srv/www/em.0x45.cz
chown drone:drone /srv/www/em.0x45.cz
```
## SSH keys
Create a keypair for SSH connection from Drone to our deployment server.
```sh
ssh-keygen -t ed25519
```
Public key has to be added to `~/.ssh/authorized_keys` of the "drone" user.
## Secrets
| | |
|-------------------|------------------------|
| `SSH_HOSTNAME` | Server hostname |
| `SSH_TARGET_DIR` | Website root directory |
| `SSH_USERNAME` | In our case "drone" |
| `SSH_PRIVATE_KEY` | Plaintext private key |

View File

@ -0,0 +1,38 @@
+++
title = "Zola website deployment with Drone CI"
date = 2022-09-28
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Zola is my SSG of choice, as it it fast, powerfull and packed in a single statically linked binary. Here is how I use with in conjuction with Drone CI for automatic building and deployment to my webserver.
<!-- more -->
I have written a [bechelor's thesis](https://git.microlab.space/em/bakalarka) on static site generators and implementing a sample website with Zola in particular. Where my thesis lacks, though, is in the automatic deployment, where I botched together some Git hooks and shell scripts. It works fairly well, but it does not provide much feedback or code validity checks.
## Pipeline
The Drone pipeline has two main parts -- building and deployment itself. I chose to download a fixed version of Zola insted of using pre-made Docker images, because they were acting out during my testing. As of today, prebuilt Zola binaries still don't work with [musl libc](https://musl.libc.org/), so a Glibc based image is needed, such as Debian instead of Alpine.
Deployment is done using [drone-rsync](https://plugins.drone.io/plugins/rsync) plugin, whcich handles connection to a remove webserver and handles private keys via Drone secrets.
```
```
## Webserver configuration
```
create user
create website directory
check permissions
```
## SSH keys
```
ssh-keygen -t rsa -b 4096
```

View File

@ -0,0 +1,75 @@
+++
title = "Zola website deployment with Drone CI"
date = 2022-09-28
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
NOTE: This article is outdated and superseded by [native Gitea Actions](@/posts/zola-deployment-with-gitea-actions-and-rsync/index.md).
Zola is my SSG of choice, as it it fast, powerful and packed in a single statically linked binary. Here is how I use with in conjunction with Drone CI for automatic building and deployment to my webserver.
<!-- more -->
I have written a [bachelor's thesis](https://git.microlab.space/em/bakalarka) on static site generators and implementing a sample website with Zola in particular. Where my thesis lacks, though, is in the automatic deployment, where I glued together some Git hooks and shell scripts. It works fairly well, but it does not provide much feedback or code validity checks.
## Pipeline
We start with a simple header in which we define the basics.
```yaml
kind: pipeline
name: default
steps:
```
The Drone pipeline has two main parts -- build and deployment. Best way of building the source is by pulling the [official Zola container from ghcr](https://github.com/getzola/zola/pkgs/container/zola). Since the container does not have a shell, we need to use `entrypoint` and `command` options, instead of a set of shell commands.
```yaml
- name: build
image: ghcr.io/getzola/zola:v0.16.1
entrypoint: [ "/bin/zola" ]
command: [ "build" ]
```
Deployment is done using [drone-rsync](https://plugins.drone.io/plugins/rsync) plugin, which handles connection to a remove webserver and can work with private keys via Drone secrets, which we configure later.
```yaml
- name: deploy
image: drillster/drone-rsync
settings:
hosts: [ "0x45.cz" ]
user: drone
source: public/*
target: /srv/www/em.0x45.cz
recursive: true
delete: true
environment:
RSYNC_KEY:
from_secret: rsync_key
```
## Webserver configuration
The server needs a new user with write access to the website root directory.
```sh
useradd drone
mkdir -p /srv/www/em.0x45.cz
chown drone:drone /srv/www/em.0x45.cz
```
## SSH keys
Create a keypair for SSH connection from Drone to our deployment server.
```sh
ssh-keygen -t ed25519
```
Public key has to be added to `~/.ssh/authorized_keys` of *drone* user on our webserver. The private key has to be inserted to Drone as a secret. This can be easily done trough the web UI, or [by using commands](https://docs.drone.io/cli/secret/drone-secret-add/). The secret name has to match `from_secret` option, so in our case: `rsync_key`. Drone can then easily authenticate and push content to our webroot.

View File

@ -0,0 +1,38 @@
+++
title = "Zola website deployment with Drone CI"
date = 2022-09-28
[taxonomies]
categories = ["Linux"]
[extra]
author = "Emil Miler"
+++
Zola is my SSG of choice, as it it fast, powerfull and packed in a single statically linked binary. Here is how I use with in conjuction with Drone CI for automatic building and deployment to my webserver.
<!-- more -->
I have written a [bechelor's thesis](https://git.microlab.space/em/bakalarka) on static site generators and implementing a sample website with Zola in particular. Where my thesis lacks, though, is in the automatic deployment, where I botched together some Git hooks and shell scripts. It works fairly well, but it does not provide much feedback or code validity checks.
## Pipeline
The Drone pipeline has two main parts -- building and deployment itself. I chose to download a fixed version of Zola insted of using pre-made Docker images, because they were acting out during my testing. As of today, prebuilt Zola binaries still don't work with [musl libc](https://musl.libc.org/), so a Glibc based image is needed, such as Debian instead of Alpine.
Deployment is done using [drone-rsync](https://plugins.drone.io/plugins/rsync) plugin, whcich handles connection to a remove webserver and handles private keys via Drone secrets.
```
```
## Webserver configuration
```
create user
create website directory
check permissions
```
## SSH keys
```
ssh-keygen -t rsa -b 4096
```

View File

@ -201,6 +201,8 @@ main {
font-family: spectral, serif; font-family: spectral, serif;
font-size: 1rem; font-size: 1rem;
} }
.all-posts { text-align: right }
} }
a { a {

1
static/favicon.svg Normal file
View File

@ -0,0 +1 @@
<svg width="400.24" height="399.294" viewBox="0 0 105.897 105.647" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path style="fill:#fff;fill-opacity:1;stroke:#182126;stroke-width:.989351;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" d="M392.684-66.342c28.97 0 52.453 23.429 52.454 52.329 0 28.9-23.484 52.328-52.454 52.329-28.97 0-52.454-23.429-52.454-52.33 0-28.9 23.485-52.328 52.454-52.328z" transform="translate(-339.735 66.836)"/><path style="fill:#fb763b;fill-opacity:1;stroke:none;stroke-width:.499999;stroke-linecap:round;stroke-linejoin:round" d="M349.6-38.438c-.163.287-.336.568-.494.858a49.242 49.242 0 0 0-3.753 8.864 48.971 48.971 0 0 0-1.973 9.647 49.705 49.705 0 0 0-.256 5.056 50.135 50.135 0 0 0 .571 7.53 49.163 49.163 0 0 0 3.324 11.715 49.11 49.11 0 0 0 4.57 8.398 49.579 49.579 0 0 0 4.41 5.6c.326.358.666.701 1.002 1.049a32.727 32.727 0 0 0 15.18-27.612 32.727 32.727 0 0 0-22.58-31.105z" transform="translate(-339.735 66.836)"/><path style="fill:#fb763b;fill-opacity:1;stroke:none;stroke-width:.844696;stroke-linecap:round;stroke-linejoin:round" d="M398.267 35.108a49.83 49.83 0 0 0 1.965-.25 49.465 49.465 0 0 0 11.743-3.315 49.375 49.375 0 0 0 10.361-5.937 49.759 49.759 0 0 0 13.926-16.053 49.214 49.214 0 0 0 4.421-11.21 49.018 49.018 0 0 0 1.304-7.301 49.682 49.682 0 0 0 .256-5.055 50.178 50.178 0 0 0-.256-5.056 49.364 49.364 0 0 0-1.304-7.3 48.965 48.965 0 0 0-3.327-9.079 49.223 49.223 0 0 0-4.959-8.147 49.68 49.68 0 0 0-8.189-8.57 49.767 49.767 0 0 0-10.038-6.414c-.147-.07-.3-.132-.447-.201a55.29 55.29 0 0 0-35.415 51.447 55.29 55.29 0 0 0 19.959 42.44z" transform="translate(-339.735 66.836)"/><path style="fill:#182126;fill-opacity:1;stroke:none;stroke-width:.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M343.332-18.436c-.055.624-.111 1.248-.143 1.878a50.167 50.167 0 0 0 .191 7.6 49.364 49.364 0 0 0 1.304 7.3 48.996 48.996 0 0 0 4.422 11.211 49.369 49.369 0 0 0 5.335 7.883 49.763 49.763 0 0 0 14.62 12.025 49.444 49.444 0 0 0 8.885 3.745 49.267 49.267 0 0 0 9.671 1.967 50.031 50.031 0 0 0 7.618.191 50.032 50.032 0 0 0 7.437-.94 49.337 49.337 0 0 0 11.499-3.871 49.444 49.444 0 0 0 8.165-4.947 49.759 49.759 0 0 0 13.926-16.053 49.214 49.214 0 0 0 4.421-11.21 49.018 49.018 0 0 0 1.304-7.301 49.682 49.682 0 0 0 .256-5.055 50.178 50.178 0 0 0-.256-5.056 49.364 49.364 0 0 0-1.304-7.3c-.068-.263-.15-.52-.222-.781l-13.433 13.015L416.763-24.4v-13.866h-24.022v-19.608L349.02-16.79z" transform="translate(-339.735 66.836)"/><path style="font-size:10.5833px;line-height:1.25;font-family:'Allerta Stencil';-inkscape-font-specification:'Allerta Stencil';fill:#fff;stroke-width:1.68486" d="M387.664 10.24h-6.303v-48.506h6.303zM360.366-1.08v-6.253l18.296-26.984v9.411L367.408-7.333h11.254v6.252z" aria-label="45" transform="translate(-339.735 66.836)"/><path style="font-size:10.5833px;line-height:1.25;font-family:'Allerta Stencil';-inkscape-font-specification:'Allerta Stencil';fill:#fff;stroke-width:1.68486" d="M392.74-38.267v27.05h3.225l.33-2.632.526-4.41v-.329c.044-.219.11-.767.197-1.645a740.857 740.857 0 0 0 1.645-11.583h18.1v-6.45zm11.978 18.363c-.526 0-1.294.044-2.303.132-.965.044-1.887.154-2.764.33l-.79 6.515c.746-.22 1.535-.374 2.37-.461a16.017 16.017 0 0 1 2.5-.198c2.589 0 4.673.724 6.253 2.172 1.623 1.448 2.435 3.422 2.435 5.923 0 3.467-.921 6.033-2.764 7.7-1.843 1.668-4.388 2.502-7.635 2.502h-8.49l-.846 5.529c2.967 0 6.152-.024 9.336 0 1.36 0 3.905.018 5.792-.29 1.886-.306 3.686-.852 5.397-1.949 1.755-1.14 3.225-2.764 4.41-4.87 1.184-2.15 1.776-5.024 1.776-8.622 0-1.843-.329-3.62-.987-5.33a14.095 14.095 0 0 0-2.896-4.608c-1.272-1.36-2.83-2.435-4.673-3.225-1.799-.833-3.84-1.25-6.12-1.25z" transform="translate(-339.735 66.836)"/></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -7,5 +7,5 @@ function filter_name(str)
} }
} }
let articles = Array.from(document.getElementsByTagName("article")); let articles = Array.from(document.querySelectorAll("article"));
document.getElementById("search").style.display = "inline-block"; document.querySelector("#search").style.display = "inline-block";

View File

@ -5,8 +5,9 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}{{ config.title }}{% endblock %}</title> <title>{% block title %}{{ config.title }}{% endblock %}</title>
<link rel="alternate" type="application/atom+xml" title="Atom" href="{{ get_url(path="/posts/atom.xml", trailing_slash=false) }}"> <link rel="alternate" type="application/atom+xml" title="Atom" href="{{ get_url(path="/atom.xml", trailing_slash=false) }}">
<link rel="stylesheet" href="/style.css"> <link rel="stylesheet" href="/style.css">
<link rel="icon" href="favicon.svg">
</head> </head>
<body> <body>
<header> <header>
@ -16,7 +17,7 @@
{% if config.extra.repository_url %} {% if config.extra.repository_url %}
<a href="{{ config.extra.repository_url }}">Source</a>, <a href="{{ config.extra.repository_url }}">Source</a>,
{% endif %} {% endif %}
<a href="{{ get_url(path="/posts/atom.xml", trailing_slash=false) }}">RSS/Atom</a> <a href="{{ get_url(path="/atom.xml", trailing_slash=false) }}">RSS/Atom</a>
</div> </div>
</div> </div>
</header> </header>
@ -38,7 +39,9 @@
<main> <main>
{% block content %} {% block content %}
{{ macros::list_posts(section="posts", count=config.extra.latest_posts_count) }} {{ macros::list_posts(section="posts", count=config.extra.latest_posts_count) }}
<a href="{{ get_url(path="/posts/") }}">All Posts &raquo;</a> <div class="all-posts">
<a href="{{ get_url(path="/posts/") }}">All Posts &raquo;</a>
</div>
{% endblock %} {% endblock %}
</main> </main>
</div> </div>

View File

@ -13,7 +13,7 @@
{% macro print_article(page, author=true) %} {% macro print_article(page, author=true) %}
<article data-title="{{ page.title | lower }}"> <article data-title="{{ page.title | lower }}">
<h2><a href="{{ page.permalink }}">{{ page.title }}</a></h2> <h2><a href="{{ page.permalink }}">{{ page.title }}</a></h2>
<p>{{ page.summary | safe }}</p> {{ page.summary | safe }}
{{ self::page_info(page=page, author=author) }} {{ self::page_info(page=page, author=author) }}
</article> </article>
{% endmacro %} {% endmacro %}