Commit Graph

51 Commits

Author SHA1 Message Date
831a1b50a4 Run the kiosk on Chromium, and take the stray media server off musicdolphin
Chromium: same page, same machine, idle, Firefox 24.2% of a core against Chromium's
11.4%. The build comes from archive.raspberrypi.com (a "+rpt" version) and is patched
for this board's V3D GPU; Debian ships a much older chromium, so the archive matters.
The whole userland here is 32-bit armhf on a 64-bit kernel, which Firefox handles worse
than Chromium does. --use-gl=egl, --enable-gpu-rasterization, --ignore-gpu-blocklist
and --enable-zero-copy are what keep rasterization on the GPU: Chromium's blocklist
does not recognise this driver and silently falls back to software without them.
pi_kiosk_browser: firefox still works, as the fallback if an update ever regresses.

Debug mode also gains xdotool, scrot and --remote-debugging-port=9222 (on 127.0.0.1),
because firing XTEST key events at a window lands about half the time and a benchmark
you cannot verify the state of is worse than none.

pi_squeezeserver gains an absent path, and mediapis.yml derives its state from
mediapi_has_squeezeserver, which defaults to false for the whole group. false means
"actively remove", not "skip": musicdolphin has been running a Logitech Media Server
that no playbook installs and nothing talks to - every squeezelite in the fleet points
at pi_squeezelite_squeezeserver (192.168.178.80, the server) - while costing ~30 MB
resident and ~47 MB of swap on a 2 GB Pi that also drives the kiosk. The absent path
stops it, purges the package, unregisters it from sysdweb, drops the port 80 -> 9000
redirect and deletes its database and logs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 15:13:16 +02:00
0cb199c403 Point musicdolphin's kiosk at the front-end's Pi profile
?pi=1 is the low-power profile added in the musicmouse repo (web/src/lib/lowPower.ts):
the ambient canvas at a quarter of the pixels and 30fps, the progress bar re-rendering
ten times a second rather than sixty, and no backdrop-filter blur. The parameter is
the whole switch, so dropping it in the address bar compares the two on one machine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 13:16:01 +02:00
a2ed74093a Give the kiosk a window manager, and a debug mode to go with it
The role ran no window manager on the theory that Firefox is the only X client and
--kiosk makes it full-screen by itself. It doesn't: --kiosk *asks* to be full-screen
over EWMH, and with no WM running nobody answers. Firefox kept its default window
size in the top-left corner - on musicdolphin's 1920x1080 monitor, a 1280x972 window
with black bands down the right edge and along the bottom, which looks exactly like
an overscan problem and isn't one. Openbox answers the request and does nothing else.

pi_kiosk_mode=debug then turns the attached screen into something workable: Firefox
as an ordinary window that is not relaunched when you close it, a visible pointer,
Openbox as the session leader with a root menu offering a terminal, and xterm,
x11-utils and mesa-utils installed. musicdolphin is set to debug for now.

The templates notify the getty handler, so a mode switch restarts the session on its
own - Xorg lives in that unit's cgroup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 13:03:14 +02:00
b3f1ff69b1 Drop the forced display mode, and let the kiosk user own its own cache
The screen was a badly seated cable - the enclosure was fouling the connector,
so the DDC and hotplug pins never mated while the video pairs partly did. That
is why it read 0 bytes of EDID on both ports and why forcing a mode "fixed" it.
With the cable seated properly HDMI-A-1 reports connected, hands over 256 bytes
of EDID and identifies itself as a DELL P2419H, so the force has nothing left to
do. Remove it and let EDID decide, which also means the mode is no longer
hardcoded to something that happened to match.

Separately, and the reason the screen then showed "Your Firefox profile cannot
be loaded": Xorg runs as root under Debian's wrapper with HOME pointing at the
kiosk user's, so the first mesa shader cache write created ~/.cache owned by
root and mode 0700. Firefox could not create ~/.cache/mozilla inside it and
never got as far as writing a profile - .mozilla/firefox held only Crash Reports
and Pending Pings, with no profiles.ini. Create ~/.cache and ~/.mozilla up front
owned by the user, so root only ever adds subdirectories to a directory the user
already owns.

Keeping the getty@tty1 enable and the userconfig.service mask: those were real
faults, not workarounds for this one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 12:26:51 +02:00
a973bc8d75 Make the kiosk autologin survive a reboot, and allow forcing a display mode
Two problems on musicdolphin, found after its first reboot.

getty@tty1 was never enabled. The role installed the autologin drop-in and the
handler restarted the unit, which works until the next boot - these images do
not enable getty@tty1 themselves, getty.target pulls in getty-static.service and
nothing else, so after a reboot nobody logs in and the kiosk never starts. Enable
it as well as starting it.

And the attached screen reads back 0 bytes of EDID on both micro-HDMI ports while
reporting "disconnected", so the kernel offers no modes, no framebuffer is
created, and X exits with "no screens found". That is the signature of a cable or
adapter whose DDC/HPD lines are broken but whose video pairs are fine. Forcing
the connector on is not enough on its own - with no EDID there is still no mode
to set - so allow a `video=` kernel parameter, which forces the output and names
the mode. hdmi_force_hotplug=1 is no use here; vc4-kms-v3d ignores it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 12:10:34 +02:00
5d853cbb8f Gate the whole of GEOlino Spezial behind the Welt 3 reward
It pointed at a 2020 episode, which locked the first handful and left the rest
of the show open - and the podcast retention cap has since deleted that episode
anyway, so the reward resolved to nothing at all.

An episode reward unlocks every episode up to and including the one named,
chronologically, so naming the newest covers the show: 356 of 356 episodes
locked until the lesson is passed, 0 after. Checked against the real library.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 10:24:21 +02:00
804cb1bfaf Give musicdolphin real sound through the HifiBerry amp
It was set up display-only, with alsa_device "simulate", so the UI showed a
working player that made no noise - but the Pi has a HifiBerry amp and
pi_alsasetup already put the softvol_effects slot on it. Point the backend at
it, the same way musicmouse does: a softvol control feeding dmix, so the card
stays shared with squeezelite and shairport instead of being locked.

Carry musicmouse's volume clamp over with it. Below roughly 23 the softvol
attenuation leaves nothing audible, and the ceiling keeps a UI slider from
putting the amp to full. Those numbers are tuned to musicmouse's speakers and
this is a different room, so they are a starting point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:53:50 +02:00
c8f19ed918 Only restart samba when its config changes
state: restarted is unconditional, so every run reported a change and bounced
smbd - which is the share the music is copied over, so a run during a transfer
would interrupt it. Start/enable it as a task, restart it from a handler the
config copy notifies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:41:50 +02:00
1b5a5e2c1d Clean up the uv installs this role used to make
It managed them, it no longer needs them, and a stray uv on PATH is a confusing
thing to find when working out how the venv got built. Nothing else on these
hosts put them there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:29:18 +02:00
9bd23467f0 Build the venv from the distribution's Python instead of uv
The backend now targets 3.11, which is what Raspberry Pi OS ships, so there is
nothing left for uv to solve. It was only ever there to obtain a 3.13 the distro
does not have, and it brought its own problems: the download had to be matched
to the Pi's 32-bit userland by hand, and no armv7 wheel exists for a 3.13 ABI,
so Pillow was compiled from source and needed image headers installed alongside.

apt for the interpreter, python3 -m venv, pip for the rest - and piwheels then
supplies prebuilt armhf wheels for the native dependencies.

A venv cannot be migrated between interpreters (it holds absolute paths into the
one that made it), and `creates:` would keep the old one forever, so check what
built it and rebuild when it does not match the current python3. That is what
carries a device off the uv-installed 3.13 without hand-holding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:21:12 +02:00
6fcc345a26 Only rebuild the venv when the deployed commit changes
The previous fix made the install convergent but not idempotent: it keyed
"changed" off uv printing "Installed", and uv prints that every single run.
musicmouse is a local path dependency, so uv rebuilds and reinstalls it every
time regardless. Every ansible run therefore restarted the service and made it
rescan the whole library for nothing.

Decide from the device instead: the commit the checkout landed on, recorded in
the venv, plus whether the venv can import the package at all. That keeps the
convergence the handler lacked - an empty venv reinstalls even when the commit
matches - without touching anything on a run where nothing moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 21:13:00 +02:00
340eeb5433 Install the backend on every run, not on a checkout change
The role left musicdolphin with an empty venv and a service crash-looping on
ModuleNotFoundError while ansible reported failed=0, because installing the
backend hung off a handler notified by the git checkout:

  - the run where the checkout changed failed later on, so handlers never
    flushed and the notification was dropped;
  - the next run found the checkout already current, notified nothing, and
    installed nothing.

Nothing ever converges from there. Make it an ordinary task that runs every
time - uv is fast when there is nothing to do, and its output says whether it
actually installed anything, so a restart is still only notified on a real
change. Give the frontend the same treatment with a cheap stat, since the build
chain has the identical hole and a device with no dist serves no UI.

Also add libjpeg-dev and zlib1g-dev: Raspberry Pi OS has a 32-bit userland,
Pillow publishes no armv7 wheel, and uv therefore builds it from source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 20:58:05 +02:00
edca1e47dc Stop the delegated frontend build from sudoing on the control machine
pi_standard_setup's defaults set `ansible_become: true`. Role defaults are
play-wide host variables, and in Ansible's precedence the `ansible_become`
variable outranks the `become` keyword - so the `become: false` on every
pi_musicmouse task delegated to localhost was silently overridden and each one
tried to sudo on the machine running ansible:

    Premature end of stream waiting for become success or become password prompt

Those defaults earn their keep bootstrapping a fresh Pi, where you connect as
`pi` and become root to enable root login, so override the variable on the
delegated tasks rather than removing them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 20:46:07 +02:00
ca0271ba44 Disable the Raspberry Pi first-boot user wizard
Removing the SSH banner only hid the symptom. userconfig.service is a
Type=oneshot unit that runs

    whiptail --inputbox "Which user would you like to rename:" 20 60 pi

on tty8 and waits for an answer, which on a headless Pi never comes - it had
been sitting in "activating" for four and a half hours on musicdolphin. It is
WantedBy=multi-user.target, so that target never finished activating either, and
the boot job for it was still queued from boot. Anything ordered
After=multi-user.target then gets a start job that queues behind it and hangs
forever: musicmouse.service never started, and the ansible task that starts it
blocked until killed.

The pi user already exists on these images, so the wizard has nothing to do.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 20:41:07 +02:00
331df52f0b Download the uv build the Pi can actually run
Raspberry Pi OS ships a 64-bit kernel with a 32-bit userland, so uname -m - and
therefore ansible_architecture - reports aarch64 on a box whose /bin/ls is
ELF32 ARM and which has no /lib/ld-linux-aarch64.so.1. The aarch64 uv tarball
unpacked happily and then failed three tasks later with

    /usr/local/bin/uv: No such file or directory

which is the dynamic loader missing, not the file, and points at entirely the
wrong thing. Pick the target triple from ansible_userspace_bits instead, which
is the fact that tells the truth, and key the install directory on the triple as
well as the version - otherwise `creates:` would keep a wrong-architecture
binary in place forever. Then run `uv --version` right after installing it, so a
bad download fails where the cause is visible.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 19:59:43 +02:00
3557fe3f2b Skip the layout guard under --check
Under --check the git task reports "changed" without writing anything, so on a
host that has not been deployed yet there is no checkout to stat and the guard
fired on a perfectly fine configuration - making `just check mediapis.yml
musicdolphin` fail before the first real run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 19:10:44 +02:00
5763df90f8 Pin each MusicMouse host to a deploy branch, and freeze musicmouse
musicmouse_version pointed both hosts at rearchitect-backend, a branch that only
ever existed on a laptop - so the previous commit's rework could never actually
have run. Point each host at a deploy/<host> branch on the remote instead. Those
branches are the deployment record: what is installed on that box right now,
moved with a force-push when you mean to deploy.

musicmouse (Kinderzimmer) is the reason this matters. It is in daily use and
still runs the pre-rearchitecture backend out of /opt/musicmouse_venv and
espmusicmouse/host_driver/main.py. That commit has no python-backend/
pyproject.toml, no python-backend/musicmouse.service and no web/ at all, so this
role cannot install it - and a run would have force-checked-out incompatible
code over a working device first and failed afterwards. Set
mediapi_install_kidsmusic: false there and leave it alone;
deploy/musicmouse records the commit that is installed, for rollback. Add a
stat + fail right after the checkout so the same mistake stops with an
explanation instead of failing three tasks deeper.

Also in the role:

- Install the typing game's curriculum next to config.yml. A config with a
  tippen: section refuses to start without it - curriculum_file is validated as
  must-exist - so musicdolphin's new config needs it present.

- Stop clobbering config.yml. The app writes to it at runtime: parent mode
  patches the volume keys and the remote-control page rewrites the remote:
  block. A plain copy: undid that on every run. Install-once by default, with
  -e pi_musicmouse_force_config=true to push a change deliberately.

- Fill out config-musicdolphin.yml against the current schema: library root and
  cache, an absolute static_dir (../web/dist would resolve to /media/web/dist
  from /media/musicmouse and silently serve nothing), tippen, and the volume
  range for a screen-driven instance. ha: is left commented out until the
  Wohnzimmer-oben entity ids are picked - the ones in the dev config are
  Arbeitszimmer. No mqtt: (it would publish a device of dead entities on a
  simulate-only host) and no lirc:/remote: (this host runs irserver, a serial
  daemon, not the lircd this speaks TCP to).

The curriculum is a verbatim copy of app content, so exclude it from
ansible-lint rather than reformat it away from its source.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 19:04:57 +02:00
9b1d01115b Deploy rearchitected MusicMouse backend + web frontend
The app grew a python-backend/ and a web/ frontend, so pi_musicmouse no
longer matches it. Rework the role:

- Install a pinned uv and build the venv with Python 3.13; Raspbian
  Bookworm's python3 is 3.11 and the backend uses PEP 695 syntax.
- pip install python-backend/ instead of a requirements.txt, and take
  the systemd unit straight from the checkout so it can't drift.
- Build web/ on the control machine (no npm on the Pi) and rsync
  web/dist over. Chain the checkout -> install -> build -> sync -> restart
  steps through handlers so a run with no repo change does nothing.
- Per-host config files (config-<host>.yml); the schema now differs
  between a host with a real mouse and a display-only one.
- Version to deploy is per host (musicmouse_version), no default.

Add pi_kiosk: autologin user running startx with Firefox in kiosk mode
and no window manager, for a Pi with a monitor attached. Enabled by
mediapi_has_monitor, defaulting off.

Turn musicdolphin into a display-only instance: serial and audio
simulated, driven entirely through the kiosk page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 17:58:51 +02:00
2443a75871 Keep /etc/hosts 127.0.1.1 in sync with the hostname
raspi-config's do_hostname rewrites the 127.0.1.1 line with
  sed "s/127\.0\.1\.1.*$CURRENT_HOSTNAME/127.0.1.1\t$NEW_HOSTNAME/"
which only matches if that line already holds the *old* hostname. Ours
still said "raspberrypi", so the substitution has been silently doing
nothing and the box could not resolve its own hostname.

Set the line explicitly instead, after the hostname is re-read, so a
rename and this update happen in the same run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 16:31:12 +02:00
ddda28be44 Remove dead host esszimmerradio
The Pi is gone; the name no longer resolves. It was still picked up by
the "hosts: all" playbooks (update-packages.yml, test_keepass.yml),
where it showed up as unreachable on every fleet run.

It was also the only host pointing pi_squeezelite_squeezeserver at
192.168.178.100 (musicdolphin) rather than the central server at .80,
so nothing depends on musicdolphin's LMS instance any more.

The "esszimmer" rows in roles/bluetooth_monitor/other/*.csv and the
analysis notebook are room labels in historical sensor training data,
not this host, and are left alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 16:28:00 +02:00
9c66b7f665 Rename musikserverwohnzimmeroben -> musicdolphin
The Pi's OS hostname was changed first (raspi-config do_hostname +
reboot), since no mediapi sets ansible_host and Ansible resolves these
by hostname via mDNS/router DNS. Host now answers as musicdolphin.local
at 192.168.178.100.

The motd file must match the live OS hostname (pi_standard_setup reads
it off the device), the host_vars filename and the pi_musicmouse config
filename must match the inventory key.

sensor_room_name/sensor_room_name_ascii stay WohnzimmerOben - they name
the physical room for MQTT topics, not the host, and renaming them would
orphan the Home Assistant history.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 16:23:00 +02:00
07e3c2797e Fix pi_standard_setup under --check
Skipped command tasks return stdout: "" rather than being undefined, so
"src: motd/{{ ...stdout }}" collapsed to "motd/" - a directory - and copy
switched to recursive mode, failing with "/etc/motd/<file>: Not a
directory". The empty boot-target stdout likewise never equals
"multi-user.target", so "Set boot mode to CLI" always reported changed.

Run the three read-only commands in check mode. They are all
changed_when: false already, so this is safe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 16:22:50 +02:00
85a26db46b single playbook for mediapis 2026-09-10 21:33:19 +02:00
dae2470e67 use same shell setup as in nix home manager 2026-09-09 08:17:48 +02:00
3d1675528b Fix tasks that always report changed regardless of actual state
Several roles reported "changed" on every playbook run even when
nothing on the target had drifted, making real config drift
indistinguishable from noise:

- 7 systemd tasks across 6 roles used state:restarted, which always
  issues a restart and always reports changed. Switched to
  state:started plus notify-driven handlers that only restart when
  the underlying unit file, script, or config actually changes.
- pi_standard_setup's boot mode, timezone, and locale tasks shelled
  out to raspi-config with changed_when:true hardcoded. Boot mode now
  checks systemctl get-default first; timezone/locale now use the
  natively idempotent community.general.timezone/locale_gen modules.
- The pi account password task computed password_hash('sha512')
  without a seed, generating a new random salt (and thus an
  apparently different hash) on every run. Added a stable seed so the
  hash only changes when the underlying secret does.

Also renamed a mislabeled task in pi_squeezelite_custom and fixed a
typo in pi_standard_setup while those files were already touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 21:28:36 +02:00
c49e4db304 Modern tools (rg, fd...) 2026-09-08 18:26:53 +02:00
f043606466 Add deliberate update playbook and unattended-upgrades role
Regular playbooks now use state: present, so they no longer upgrade
packages as a side effect. This adds two separate, explicit mechanisms
to keep the fleet patched instead:

- update-packages.yml: ad hoc / to-be-scheduled fleet-wide upgrade
  (safe by default, dist available via -e), plus
  update-packages-pinned-example.yml as a template for pinning or
  bumping a single package outside that.
- roles/unattended_upgrades: automatic security-only patching via
  unattended-upgrades, with a scheduled reboot window and mail
  left disabled pending a configured MTA. Applied to every host in
  full.yml and server.yml.

Also removes a leftover `upgrade: yes` apt task from pi_standard_setup
and server_basic_environment that was still doing a full upgrade on
every routine run, defeating the point of the state: present switch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 18:02:41 +02:00
37b75ecf81 Fix remaining ansible-lint violations: file permissions, var-naming, package pinning
- risky-file-permissions (32): add explicit mode: to copy/template/file tasks,
  matching the umask-derived permissions they already had (0644 for configs
  and systemd units, 0755 for created directories) — no functional change.
- var-naming (28): prefix role-scoped vars with their role name across
  pi_dhtsensor, pi_dhtsensor_circuitpython, pi_shairport, pi_squeezelite,
  pi_squeezelite_custom, pi_sispmctl, pi_standard_setup, and pi_sysdweb's
  sysdweb_name (shared by 9 consuming roles). Updated every dependent
  template, task reference, and matching inventory.yml override, and
  verified resolved values with ansible-inventory before/after.
- Fixes a latent bug found while renaming: pi_standard_setup's "Get/Change
  WiFi country" tasks reused the name wifi_country for both the role default
  and a register, so the register silently clobbered the default before
  do_wifi_country ever read it. Split into distinct names so the intended
  default value is used.
- package-latest (2): pin docker-ce/docker-compose-plugin installs in
  server_debian_docker to state: present.
- no-handler (1): move pi_lirc's "Reboot if boot overlay changed" into a
  proper handler notified by the boot-overlay task.

ansible-lint now passes clean at the production profile.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 17:28:12 +02:00
bb72eaec10 Untrack local .ansible runtime cache and fix stale gitignore path
The .ansible directory is a local ansible-galaxy/ansible-core cache
that got swept into the previous commit by git add -A. Also update
the pi-squeezeserver backup ignore path to match the role rename.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 17:13:39 +02:00
ab9763ec49 Fix ansible-lint violations: FQCN, formatting, bugs, role renames
- Auto-fix FQCN, YAML formatting, jinja spacing, and free-form module
  syntax via ansible-lint --fix
- Fix comments misplaced inside module args by the auto-fixer
  (bluetooth-monitor, pi_standard_setup, pi_musicmouse)
- Fix notify: references left stale (lowercase) after handler names
  were re-cased, which would have silently broken reboot/restart
  handlers (pi_disable_onboard_bluetooth, pi_hifiberry_amp,
  pi_squeezelite, pi_standard_setup)
- Fix a task in pis/debmatic-install.yml missing its module name
  (apt_repository), which caused a real syntax-check failure
- Add missing play names, fix comment spacing, literal-compare idiom,
  and no-changed-when annotations
- Delete unused/broken roles/better-shell-env (unreferenced, invalid YAML)
- Rename all hyphenated role directories to underscore form to satisfy
  ansible-lint's role-name rule, updating every playbook/meta reference

Remaining lint findings (var-naming, package-latest, risky-file-permissions,
no-handler) intentionally left for follow-up per user decision.
2026-09-08 17:13:00 +02:00
f79c106437 Automated repo cleanup with claude 2026-09-08 16:52:46 +02:00
5642424697 before cleanup 2026-09-08 16:32:02 +02:00
7c70221723 IR stuff update 2025-01-06 18:01:18 +01:00
Martin Bauer
9092f08481 Bt monitor 2024-07-28 08:45:01 +02:00
Martin Bauer
e9ec94a5f8 Bluetooth Monitor WIP 2024-03-29 09:32:59 +01:00
Martin Bauer
fe744b2285 bt monitor 2024-03-08 13:02:55 +01:00
Martin Bauer
ffeee72652 music mouse setup 2024-03-08 13:02:43 +01:00
Martin Bauer
fb6f10891d Bluetooth monitor and more 2024-03-01 15:01:08 +01:00
Martin Bauer
7501ef18a4 updates raspis to new os based on bookworm 2024-02-19 08:10:58 +01:00
Martin Bauer
7776095180 New server setup based on ubuntu 2023-09-19 10:55:47 +02:00
Martin Bauer
578be1a1cf updates 2023-01-03 20:07:56 +01:00
Martin Bauer
2a251d2700 Server scripts 2021-09-11 10:18:47 +02:00
Martin Bauer
f1d104a224 Updates & fixes 2021-07-20 15:35:12 +02:00
Martin Bauer
6c421a4ae1 Octopi & dht fixes 2021-07-05 19:50:15 +02:00
Martin Bauer
23a2c1fb50 added ir server, squeeze server, ... 2020-05-16 18:35:44 +02:00
Martin Bauer
93034dd0ec Update dht22 sensing code + sispmctl fixes 2020-05-12 20:51:04 +02:00
Martin Bauer
d8c9a491d1 Working sound setup for raspis 2020-05-10 15:25:38 +02:00
Martin Bauer
caf6232dfb Added sysdweb 2020-05-02 11:21:52 +02:00
Martin Bauer
4308dae03d Ansible files 2020-03-30 22:49:44 +02:00
Martin Bauer
274f15b213 update 2020-01-16 21:09:14 +01:00