feat(jmri): headless JMRI server with Leviton layout power monitor and X11 GUI mode

- Stable udev device symlinks (/dev/jmri/nce, /dev/jmri/loconet, /dev/jmri/lcc)
- jmri-monitor: polls Leviton Decora Smart switch to start/stop JMRI automatically
  - Quiet hours 1-10 AM (no polling)
  - 30s off-delay before shutdown
- LCRR config cloned from Gitea (ssh://gitea.mk-labs.cloud:2221/rblundon/LCRR.git)
- ~/.jmri symlinked to LCRR repo for GitOps config management
- jmri-gui: X11 remote GUI access (PanelPro/DecoderPro) via ssh -X as jmri user
  - Stops daemon, launches GUI, restarts daemon on exit if layout still on
- jmri user gets login shell + SSH key for GUI sessions
- Full JRE installed (openjdk-21-jre) for AWT/X11 support
This commit is contained in:
Hermes Agent service account committed 2026-07-29 00:43:23 -05:00
1 parent a5433dcb5b
commit d974c75d7c
26 files changed
+2460 -459

No files matched your search

@@ -0,0 +1 @@
{"nodes": [{"id": "home_hermes_git_homelab_ansible_roles_observer_files_grafana_provisioning_dashboards_main_cadvisor_json", "label": "cadvisor.json", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L1"}, {"id": "main_cadvisor_inputs", "label": "__inputs", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L2"}, {"id": "main_cadvisor_requires", "label": "__requires", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L12"}, {"id": "main_cadvisor_annotations", "label": "annotations", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L38"}, {"id": "main_cadvisor_annotations_list", "label": "list", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L39"}, {"id": "main_cadvisor_editable", "label": "editable", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L51"}, {"id": "main_cadvisor_gnetid", "label": "gnetId", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L52"}, {"id": "main_cadvisor_graphtooltip", "label": "graphTooltip", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L53"}, {"id": "main_cadvisor_id", "label": "id", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L54"}, {"id": "main_cadvisor_iteration", "label": "iteration", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L55"}, {"id": "main_cadvisor_links", "label": "links", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L56"}, {"id": "main_cadvisor_panels", "label": "panels", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L57"}, {"id": "main_cadvisor_schemaversion", "label": "schemaVersion", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L743"}, {"id": "main_cadvisor_style", "label": "style", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L744"}, {"id": "main_cadvisor_tags", "label": "tags", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L745"}, {"id": "main_cadvisor_templating", "label": "templating", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L746"}, {"id": "main_cadvisor_templating_list", "label": "list", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L747"}, {"id": "main_cadvisor_time", "label": "time", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L804"}, {"id": "main_cadvisor_time_from", "label": "from", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L805"}, {"id": "main_cadvisor_time_to", "label": "to", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L806"}, {"id": "main_cadvisor_timepicker", "label": "timepicker", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L808"}, {"id": "main_cadvisor_timezone", "label": "timezone", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L809"}, {"id": "main_cadvisor_title", "label": "title", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L810"}, {"id": "main_cadvisor_uid", "label": "uid", "file_type": "code", "source_file": "ansible/roles/observer/files/grafana/provisioning/dashboards/main/cadvisor.json", "source_location": "L811"}, {"id": "main_cadvisor_version", "label": "version", "file_type": "code", "source_file": "ansible/roles/observer/files/grafanaLine truncated