2026-08-01 16:03 vor Beginn auf echter Hardware

This commit is contained in:
Dieter Lang 2026-08-01 16:04:15 +02:00
parent afdbb2e136
commit f29a8bbd8d
14 changed files with 190 additions and 4 deletions

13
app_spannung/config.json Normal file
View file

@ -0,0 +1,13 @@
{
"web_port": ":8080",
"i2c_bus": "/dev/i2c-1",
"ads1115_address": 72,
"voltage_factor_1": 5.0,
"voltage_factor_2": 5.0,
"relais_pins": [
{"id": 1, "name": "Relais 1 (Hauptschalter)", "gpio": "GPIO12"},
{"id": 2, "name": "Relais 2 (unbenutzt)", "gpio": "GPIO16"},
{"id": 3, "name": "Relais 3 (unbenutzt)", "gpio": "GPIO20"},
{"id": 4, "name": "Relais 4 (unbenutzt)", "gpio": "GPIO21"}
]
}

BIN
app_spannung/spannung-amd64 Executable file

Binary file not shown.

BIN
app_spannung/spannung-arm32_6 Executable file

Binary file not shown.

BIN
app_spannung/spannung-arm32_7 Executable file

Binary file not shown.

BIN
app_spannung/spannung-arm64 Executable file

Binary file not shown.

View file

@ -0,0 +1,31 @@
# ==============================================================================
# KURZANLEITUNG ZUR INSTALLATION UND VERWALTUNG
# ==============================================================================
# 1. Datei kopieren nach: /etc/systemd/system/spannung.service
# 2. Systemd neu laden: sudo systemctl daemon-reload
# 3. Autostart aktivieren: sudo systemctl enable spannung.service
# 4. Dienst starten: sudo systemctl start spannung.service
# ==============================================================================
[Unit]
Description=Spannung Control Service
After=network-online.target i2c.service
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
ExecStartPre=/bin/bash -c 'for i in {1..10}; do i2cdetect -y 1 | grep -E "^40:" | grep -q -E "\b48\b" && exit 0; echo "warte auf ADS1115..."; sleep 2; done; exit 1'
ExecStart=%h/spannung/app/spannung-arm32_7
WorkingDirectory=%h/spannung/app
User=%u
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60s
StartLimitBurst=3
StandardOutput=append:%h/spannung/app/spannung.log
StandardError=append:%h/spannung/app/spannung.log
[Install]
WantedBy=multi-user.target

10
app_spannung/version.json Normal file
View file

@ -0,0 +1,10 @@
{
"version": "0.1",
"date": "06.06.2026 um 20:57",
"description": "Messung von zwei Spannung und Steuerung von Relais",
"features": [
"ADS1115-Abfrage über go-i2c",
"Weboberfläche mit Steuerbuttons für Reilais",
"Definiton der GPIO in der config.json"
]
}

View file

@ -0,0 +1,77 @@
package web
import (
"html/template"
"net/http"
"strconv"
)
type RelaisData struct {
ID int
Name string
State bool
}
// TemplateData erweitern um Version und Datum
type TemplateData struct {
V1 float64
V2 float64
Relais []RelaisData
Version string
BuildDate string
}
type Server struct {
port string
readVoltFunc func(channel int) float64
toggleFunc func(id int)
getRelais func() []RelaisData
versionFunc func() (string, string) // Neu hinzugefügt
}
// NewServer um das version-Callback erweitern
func NewServer(port string, readVolt func(int) float64, toggle func(int), getRelais func() []RelaisData, getVersion func() (string, string)) *Server {
return &Server{
port: port,
readVoltFunc: readVolt,
toggleFunc: toggle,
getRelais: getRelais,
versionFunc: getVersion,
}
}
func (s *Server) Start() error {
http.HandleFunc("/", s.handleIndex)
http.HandleFunc("/toggle", s.handleToggle)
return http.ListenAndServe(s.port, nil)
}
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
v1 := s.readVoltFunc(0)
v2 := s.readVoltFunc(1)
ver, date := s.versionFunc() // Version abfragen
tmpl, err := template.ParseFiles("web/static/index.html")
if err != nil {
http.Error(w, "Template nicht gefunden: "+err.Error(), http.StatusInternalServerError)
return
}
data := TemplateData{
V1: v1,
V2: v2,
Relais: s.getRelais(),
Version: ver, // Daten an Template übergeben
BuildDate: date, // Daten an Template übergeben
}
tmpl.Execute(w, data)
}
func (s *Server) handleToggle(w http.ResponseWriter, r *http.Request) {
idStr := r.URL.Query().Get("id")
id, err := strconv.Atoi(idStr)
if err == nil {
s.toggleFunc(id)
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}

View file

@ -0,0 +1,55 @@
<!DOCTYPE html>
<html>
<head>
<title>Funkstation Steuerung</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: 'Segoe UI', Arial, sans-serif; text-align: center; background: #0f172a; color: #f8fafc; padding: 20px; }
.container { max-width: 500px; margin: 0 auto; }
.card { background: #1e293b; padding: 20px; margin: 15px 0; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.3); border: 1px solid #334155; }
.val { font-size: 2.5em; color: #38bdf8; font-weight: bold; font-family: monospace; }
.grid { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 15px; }
.btn { width: 100%; padding: 14px; font-size: 1.1em; border: none; border-radius: 8px; cursor: pointer; font-weight: bold; transition: background 0.2s; color: white; }
.btn-on { background: #ef4444; }
.btn-on:hover { background: #dc2626; }
.btn-off { background: #10b981; }
.btn-off:hover { background: #059669; }
.footer-nav { margin-top: 25px; font-size: 0.9em; color: #64748b; }
</style>
<meta http-equiv="refresh" content="3">
</head>
<body>
<div class="container">
<h1>U12V Funkstations-Monitor</h1>
<div class="card">
<h3>Spannungsebene 1</h3>
<div class="val">{{printf "%.2f" .V1}} V</div>
</div>
<div class="card">
<h3>Spannungsebene 2</h3>
<div class="val">{{printf "%.2f" .V2}} V</div>
</div>
<div class="card">
<h3>Relaissteuerung</h3>
<div class="grid">
{{range .Relais}}
<a href="/toggle?id={{.ID}}" style="text-decoration: none;">
<button class="btn {{if .State}}btn-on{{else}}btn-off{{end}}">
{{.Name}}: {{if .State}}AKTIV (Ausschalten){{else}}INAKTIV (Einschalten){{end}}
</button>
</a>
{{end}}
</div>
</div>
<div class="footer-nav">
Aktualisiert alle 3 Sekunden automatisch<br>
<span style="font-size: 0.8em; color: #475569; margin-top: 5px; display: block;">
Version v{{.Version}} ({{.BuildDate}})
</span>
</div>
</div>
</body>
</html>

View file

@ -5,9 +5,9 @@
"voltage_factor_1": 5.0,
"voltage_factor_2": 5.0,
"relais_pins": [
{"id": 1, "name": "Relais 1 (Hauptschalter)", "gpio": "GPIO22"},
{"id": 2, "name": "Relais 2 (unbenutzt)", "gpio": "GPIO23"},
{"id": 3, "name": "Relais 3 (unbenutzt)", "gpio": "GPIO24"},
{"id": 4, "name": "Relais 4 (unbenutzt)", "gpio": "GPIO25"}
{"id": 1, "name": "Relais 1 (Hauptschalter)", "gpio": "GPIO12"},
{"id": 2, "name": "Relais 2 (unbenutzt)", "gpio": "GPIO16"},
{"id": 3, "name": "Relais 3 (unbenutzt)", "gpio": "GPIO20"},
{"id": 4, "name": "Relais 4 (unbenutzt)", "gpio": "GPIO21"}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.