hledger: track if BahnCard was worth it

In November 2021 I got offered a 30€ discount on the BahnCard25 from the Deutsche Bahn AG. Some time ago I cancelled my BahnCard because I wasn't using it enough to justify having one. With a 30€ discount I should have no problem getting the remaining 25.7€ of value back.

But I wanted to track this. I am using hledger to track all my expenses and assets.

The ledger statement for the Bahncard looks like this:

2021-11-24 BahnCard 25
Expenses:misc:Bahncard                     €25.7
Assets:Checking Account
(worthIt:Bahncard2022)                     €55.7  ; full price
(worthIt:Bahncard2022)                      €-30  ; discount

And one statement of the travels looks like this:

2022-01-04 Travel S->KA
Expenses:Travel:Deutsche Bahn             €10.65
Assets:Checking Account
(worthIt:Bahncard2022)                    -€3.55

Result of my current balance:

hledger reg ^WorthIt:Bahncard2022

Date

Description

Account

Amount

Balance

2021-11-24

BahnCard 25

(worthIt:Bahncard2022)

€55.70

€55.70

(worthIt:Bahncard2022)

€-30.00

€25.70

2022-01-04

Travel S->KA

(worthIt:Bahncard2022)

€-3.55

€22.15

2022-01-04

Travel KA->S

(worthIt:Bahncard2022)

€-3.55

€18.60

2022-01-06

Travel S->KA

(worthIt:Bahncard2022)

€-3.55

€15.05

2022-01-06

Travel KA->S

(worthIt:Bahncard2022)

€-3.55

€11.50


Now I have about 10 months to use my BahnCard25 and save the remaining 11.50€.
That should be possible. :)

Scrape a Website using Playwright Python

I build a crawler to get the waterlevels of rivers in Baden-Württemberg every 15 minutes. There is no real API, but I wanted to plot the data over time. The page is rendered using Javascript which made a beautifulsoup solution not possible.

But there is Playwright for Python.

Playwright works with multiple browsers and supports an interactive mode.

As example for the waterlevel website:

import asyncio
from playwright.async_api import async_playwright

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()
        await page.goto("https://www.hvz.baden-wuerttemberg.de/overview.html")
        print(await page.title())
        # pause to inspect the page
        await page.pause()
        await browser.close()

asyncio.run(main())

This starts an interactive chromium. F12 is available and every page.pause() is a breakpoint. The page is paused after printing the title of the website.

/images/playwright_inspector.png

The interactivity and full debug capabilities allow a lot easier development than using beautifulsoup on a downloaded HTML file.

The crawler is using GitHub Actions to download the data using schedules.

Download your data from Oura

The OuraRing is a sleep and activity tracker in the form factor of a ring.
I have a black one since end of 2020 and I am very happy with the insights about my sleep.

At the end of October 2021 Oura announced a new OuraRing (Gen3) - but this time with a subscription requirement.
The old rings have no monthly fee (all Gen1+Gen2 rings won't require a subscription in the future).
Every old customer gets a free lifetime subscription, but is forced to buy a new Gen3 ring until 2021-11-09.
I don't want to be forced into replacing a perfectly working device. So no thanks!

I cannot trust Oura anymore after this move so I decided it is time to write a downloader for the past days I used my Oura ring.
My plan is to use the ring until it breaks and than search for an alternative. But no OuraRing for sure.

Thanks to python-ouraring the downloader was easy to bootstrap.
My code downloads the daily data for sleep, activity, readiness and ideal bedtime.
This data is written into a sqlite database for future analysis.

The repo with the downloader: https://github.com/mfa/oura-to-sqlite.
The only thing needed is a personal access token from Oura.