~derf

You have reached the personal homepage of an entity commonly known as derf / derfnull / Birte Friesel. Hi! 👋

If you are looking for the more professional side of me, you may take a look at my Publications (see below) or head directly to my work homepage: Dr. Birte Kristina Friesel @ Universität Osnabrück

Resources

Contact

You can reach me by E-Mail (d​erf@fina​lr​ewind.org) and on IRC (derf0 @ OFTC, hackint). My PGP key for E-Mail encryption is 64FE6EC0 55560F9E F13A3044 19E6E524 EBB177BA. I occasionally post stuff on the Fediverse (@derf@social.skyshaper.org).

The remainder of this page duplicates a curated sub-set of projects and the latest blog entries.

Projects

> dbris 'Eichlinghofen H-Bahn, Dortmund' 'Dortmund Hbf'

19.01. 16:51  (00:21)  17:12   .  Bus  S

Bus 440 → Oespel S-Bahnhof, Dortmund
16:51 (+1)  ab  Eichlinghofen H-Bahn, Dortmund
16:56 (+1)  an  Oespel S-Bahnhof, Dortmund

Fußweg 46m  (≈ 3 min.)
S 1 → Dortmund Hbf   .
17:01 (+5)  ab  Dortmund-Oespel  2
17:12 (+2)  an  Dortmund Hbf  7
> hafas 'Eichlinghofen H-Bahn, Dortmund' 'Dortmund Hbf'

00:15        Schw-B HB5  (0:03)  S 1

Schw-B HB5 → Universität S-Bahnhof, Dortmund
21:51  ab  Eichlinghofen H-Bahn, Dortmund
21:55  an  Universität S-Bahnhof, Dortmund

Walk 37m  (approx. 3 minutes)
S 1 → Dortmund Hbf
21:58  ab  Dortmund Universität: 2
22:06  an  Dortmund Hbf: 4
> efa Essen Martinstr Düsseldorf Hbf
14:34 ab  Essen Martinstr.: Bstg. 1      Straßenbahn 108      Essen Altenessen Bf Schleife
14:38 an  Essen Hauptbahnhof: Bstg. 1

14:47 ab  Essen Hauptbahnhof: 2          R-Bahn RE11 (RRX)    Düsseldorf Hbf
15:24 an  Düsseldorf Hbf: 10
> dbris-m 'Bochum Hbf'
06:39  ( +7)   ICE 843                             Berlin Hbf  5
06:39  ( +7)   ICE 853                             Berlin Hbf  5
06:51  (+19)       S 1                              Essen Hbf  7
06:37  ( +1)   ICE 527                            München Hbf  3
Zug fährt abweichend mit nur einem Zugteil. Die Wagen 31 - 39 entfallen.
> hafas-m 'Hamburg Dammtor'
13:49  ( +1)  RE 7     Flensburg                  3
13:49  ( +1)  RE 7     Kiel Hbf                   3
13:49         S 5      Buxtehude                  2
13:50  ( +4)  Bus 5    Nedderfeld, Hamburg
13:50         U 1      Ohlstedt, Hamburg
> efa-m -s VVO Dresden Hbf
13:40 ( -2)  5      66           Lockwitz
13:41        3      3         .  Wilder Mann
13:44        4      3         .  Coschütz
13:44        6      66           Freital-Deuben
13:46 ( +4)  6      360          Kurort Altenberg Bahnhof
13:46        5      360          Dresden Ammonstraße / Budapester Straße
13:48 ( +1)  1      7         *  Weixdorf
13:51        1      10        .  Tolkewitz
13:52        Gl.10  RE3          Hof Hbf

News

Travel-Status-DE-IRIS-2.01.tar.gz (signature)

  • Update DB InfraGO delay / QoS codes

Travel-Status-DE-DBRIS-0.19.tar.gz (signature)

  • DBRIS->new, ->new-p: Add optional num_vias key
  • Journey: rename train, train_no to trip, trip_no. The former accessors are now deprecated and will issue a run-time warning when used.
  • Journey->trip, ->trip_no: Improve handling of combined operator / line number prefixes; avoid using trip number as type / line number
  • Journey: New accessors: types, type_at
  • Location: new accessors: operator, trip_type
  • dbris-m: Add -Or / -Oa options (show next stops of all departures)
  • dbris-m: Add --route-entries option
  • dbris-m: Provide more detailed operator information, if available

Travel-Status-DE-HAFAS-6.24.tar.gz (signature)

  • station: Fix result->station->{eva} key

Travel-Status-DE-VRR-3.18.tar.gz (signature)

I'm a sucker for colourful Grafana graphs (and not-necessarily-useful data logging in general), so naturally, I also had to see if I could get some hardware stats from my Steam Deck in there. Turns out: thanks to Deck's Linux foundation, this is quite easy. All you need to do is enable SSH access (or work directly on the device) and set up a systemd user timer with whatever kind of data logging you want. In my case, I did the following:

  • Switch to desktop mode
  • Open konsole (i.e., the terminal app)
  • Run passwd to set a password for the deck user
  • ssh deck@steamdeck from my workstation
  • Install a script for InfluxDB logging in ~/bin
  • Install a user service and associated timer in ~/.config/systemd/user to run this script every few minutes
  • Enable the timer

My script looks as follows:

#!/bin/sh

HOST=steamdeck

exec curl -s -XPOST 'https://[…]/influxdb/write?db=hosts' \
--data "
memory,type=embedded,host=${HOST} $(free -b | awk '($1 == "Mem:") { printf "used_bytes=%d,used_percent=%f", $2 - $7, ($2 - $7) * 100 / $2 }')
$(awk '($1 ~ /^(.*):$/) { gsub(/:/, "", $1); printf "interface,type=embedded,host='${HOST}',name=%s rx_bytes=%d,rx_drop_count=%d,tx_bytes=%d,tx_drop_count=%d\n", $1, $2, $5, $10, $13 }' /proc/net/dev)
$(df -B1 | awk '($1 != "Filesystem") { gsub(/%/, "", $5); printf "filesystem,type=embedded,host='${HOST}',device=\"%s\",mountpoint=\"%s\" total_bytes=%d,used_bytes=%d,available_bytes=%d,used_percent=%d\n", $1, $6, $2, $3, $4, $5 }')
load,type=embedded,host=${HOST} $(awk '{print "avg1=" $1 ",avg5=" $2 ",avg15=" $3}' /proc/loadavg)
users,type=embedded,host=${HOST} $(who | awk '($5 !~ /tmux/) {logins++} END { printf "login_count=%d,session_count=%d", logins, NR }')
battery,type=embedded,host=${HOST},id=1 capacity_percent=$(cat /sys/class/power_supply/BAT1/capacity),cycle_count=$(cat /sys/class/power_supply/BAT1/cycle_count),voltage_uv=$(cat /sys/class/power_supply/BAT1/voltage_now)
$(for i in /sys/class/thermal/thermal_zone*; do test -r $i/type && test -r $i/temp && echo "sensor,type=embedded,host=${HOST},name=$(cat $i/type) mdegc=$(cat $i/temp)"; done)
"

This gives me stats about memory and disk (SSD + µSD) usage, load, and current battery charge and voltage. Unfortunately, power readings do not seem to be available.

For instance, the following screenshots show an evening DOOM session, followed by leaving the Deck idle to finish some downloads.

They allow for insights such as:

  • The Steam Deck typically reaches 80°C when running hardware-intensive games
  • Battery drain really depends a lot on what kind of game you're playing
  • The Lenovo USB-C Slim Travel Dock I'm using for working at home works just fine with the Steam Deck, but fails to negotiate proper power delivery, so the battery slowly drains when playing.

Recently, I managed to drop my Canon EOS M50 while changing lenses. The fall wasn't that high (maybe 20cm, give or take), but exerted enough force on the body to dislodge the viewfinder's eyecup. This caused the viewfinder's proximity sensor to always detect something (namely, the eyecup's plastic), which, in turn, meant that the camera would no longer operate its 3" LCD – after all, someone was using the viewfinder, so better turn it off in order to save power.

Trying to shove the eyecup back into place did not work at all, and the fact that Canon does not treat it as user-serviceable or -replaceable did not bode too well. After a few weeks' worth of hesitation, I decided to try disassembling the camera up to the eyecup and repair / re-align it myself. It was long out of warranty, so at least I culd not void anything by trying my luck. There was just the risk of “verschlimmbessern” (making something worse by trying to improve), i.e., breaking the camera entirely when trying to repair it.

So, as usual: only do this if you know what you're doing, and don't blame me if something breaks.

Disassembly

Getting to the eyecup requires removal of nine (black, plastic?) PH0 screws and two parts of the camera's plastic shell. I did not check the screw types thoroughly – they all seemed quite similar, but I still made sure to re-apply each screw to the correct hole just to be on the safe side.

First, remove the microphone and NFC cover on the left. It is held in place by three screws, and can be carefully lifted out once they are loose. There are no plastic clips or anything, so you should not need to apply force.

Then, flip out the 3" LCD so that it is out of the way and reveals two screws below the viewfinder. Remove these, the two screws at the tripod mount, and the two screws on the right side. The plastic part that you can now remove holds control button and is connected to the camera with a flat flex cable right below the control buttons. So, carefully fold out the plastic back (including the control buttons), and tilt it to the right to avoid stressing said cable. You only need to rotate it by about 90° in order to expose the final (tenth) screw securing the eyecup. You can choose between disconnecting it and storing it somewhere safe, or leaving it connected and being extra careful not to break it.

Repair

Now, remove the metal screw holding the eyecup. In my case, once the screw was out, I could easily move the eyecup back into place (without having to exert force) and was already done with the repair. I expect that you can also replace the entire eyecup at this point, but I did not try that.

Re-Assembly

  • Secure the eyecup with the metal screw
  • Reconnect the flat flex cable leading to the control buttons on the back cover
  • Snap the back cover back into place. Do not secure it yet.
  • Turn on the camera and verify that eyecup / viewfinder, 3" LCD, and the control buttons on the back (next to the LCD) are working
  • Turn the camera off
  • Secure the back cover with its six black screws
  • Snap the side cover back into place
  • Secure the side cover with its thre black screws

In my case, I did not verify that the control buttons are working before re-applying all screws. While I had not unplugged the flat flex cable, I had still managed to loosen its connector, so I had to go back and re-connected it in order to have a working camera again. Before proceeding with the re-assembly, the connector should look roughly like this:

Apart from that, this was a pleasantly straightforward repair, and definitely better than just not using the LCD anymore.

Travel-Status-DE-DBRIS-0.18.tar.gz (signature)

  • dbris-m: Show trip number changes along the route, if any
  • Journey: Fix ->operator and ->train_no accessors
  • Journey: New accessors: trip_numbers, trip_no_at
  • Location: New accessor: trip_no

Travel-Status-DE-DBRIS-0.17.tar.gz (signature)

  • Journey: New accessors: admin_id, admin_ids, operator, operators
  • New build dependencies: File::Slurp, JSON

Travel-Status-DE-DBRIS-0.16.tar.gz (signature)

  • Formation::Group: Add ICE L and LINT 41; fix CFL KISS detection

Travel-Status-DE-DBRIS-0.15.tar.gz (signature)

  • DBRIS: Add optional failure_cache key to new / new_p. This causes the module to cache failed requests, thus decreasing the risk of running into rate limits when, e.g., requesting carriage formation data that is not available upstream.
  • Formation::Group: Update carriage name list (patch by Lili Chelsea Urban)

Travel-Status-DE-VRR-3.17.tar.gz (signature)

  • New dependency: URI::Escape
  • URL-Escape umlauts in name/place parameters sent to EFA backends. This fixes umlaut-related issues in LinzAG and VVO requests.
  • EFA: Detect "invalid stop" backend errors.
  • EFA(3pm): Remove efa_encoding, which has been unsupported for a long time already.

Travel-Status-DE-VRR-3.16.tar.gz (signature)

  • Add AVV ("AVV Augsburg", not Aachen) service definition

Travel-Status-DE-DBRIS-0.14.tar.gz (signature)

  • dbris-m: Do not break --json/--raw-json if the requested stop name is not an exact match
  • Location: Set is_additional for additional stops based on text remarks

Travel-Status-DE-IRIS-2.00.tar.gz (signature)

  • Update station database
  • db-iris and Travel::Status::DE::IRIS are still deprecated, but as the backend service is still available, we might as well make the most of it
  • The major release is mandated by Perl's standard versioning scheme. There are no backwards-incompatible changes.

On the fourth and final full day of our vacation in the Giant Mountains, we decided to go for a change of scenery: take the train to Szklarska Poreba (Schreiberhau), walk up to Pramen Labe (Elbquelle / spring of the Elbe river), and then, depending on time of day and our appetite for more, either take the train back to Karpacz or walk back there across the peaks of the Giant Mountains. Unsurprisingly, we ended up walking the 20km or so from Pramen Labe back to Karpacz, and I can only say that that was the best decision we could have made.

  • KD D62 Karpacz (09:00) → Jelenia Góra (09:18)
  • KD D6 Jelenia Góra (09:24) → Szklarska Poreba Górna (10:15)

Pramen Labe

Szklarska Poreba is a comfortable little town, and seems like less of a tourist attraction than Karpacz. Only downside: it's located in a valley, with the train station where we got off sitting on the hills on one side and the Giant Mountains on the other. So, we first had to lose some precious elevation only to climb back up again on the other side. Apart from that, the way up went as usual: it started out relatively smooth and even, and then got steep and stony. There were some more stone formations and water streams, but nothing out of the ordinary.

Pramen Labe was pretty crowded, so we didn't stay for too long (13:30 to 14:00 or so). The spring itself is your typical ordinary spring, augmented with a nice list of some of the towns and cities it passes before it finally flows into the North Sea. It's located on a relatively large plateau, so from the spring itself, you don't have that much of a view into the surrounding mountain- or countryside.

The Ridge

The first peak we passed was Violik / Łabski Szczyt (Veilchenstein / violet peak). Apparently, its granite rock is slowly ground down by freezing water, leading to its slightly unnatural look as if someone had used a large shovel to pile up a heap of stones. It was also home to some prime specimen of some kind of moss, possibly Trentepohlia iolithus (Veilchenmoos) or Psilolechia lucida (Schwefelflechte).

Up next were Vysoká pláň (high plain), a small peak located on a wide plateau that sits at about 1,400 metres above sea level, and the neighbouring Śnieżne Kotły (Schneegruben / snow pits). Vysoká pláň features the former Schronisko „Nad Śnieżnymi Kotłami” (Schneegrubenbaude / shelter “above the snow pits”), which used to offer rest to hikers and mountain climbers. These days, it is instead used as a radio tower: Radiowo-telewizyjny Ośrodek Nadawczy Śnieżne Kotły. Śnieżne Kotły tend to be a repository for not-yet-molten snow late into spring, but were absolutely devoid of it when we passed them in early August. In any case, the view from the upper side of the cliff was quite spectacular. We spent a few minutes admiring the views, and continued at about 15:00.

We continued around Vysoké kolo (Hohes Rad / high wheel), whose peak consists entirely of broken granite, towards Špindlerova bouda (Spindlerbaude / Špindler's hut), a former shelter that now serves as a hotel.

The peak of vysoké kolo really is quite impressive – I only have pictures of the hiking path around it; see the Wikipedia links for more. Some of the rocks on the path are loose and there are no handrails or anything – do be careful where you step.

The remainder of the way towards Špindlerova bouda provided more granite heaps, mountain pines, and other kinds of rock formations. Also, Špindlerova bouda itself actually features a bus stop, located at convenient 1,198 metres above sea level.

Descent

From here on, continuing the path along the peaks would have taken us to Słonecznik, which we had already visited two days ago. Instead, we descended to the north. We had actually planned to make our descent before Špindlerova bouda, however, it turned out that that path was closed to hikers.

At this point, the clock was reading 17:00, we still had quite a few kilometres left to go, and the shadows were already growing longer. We had the sun at our backs and got some nice views across the Polish lowlands, plus the usual selection of rocks, more or less forested areas, and marsh lands. We reached Polana - Kotki (Katzenschlosslichtung / cat castle glade) at 18:45, and got back to Karpacz at around 20:15.

See lib.finalrewind.org/Pramen Labe for more pictures.