2026-08-02 09:08 nur wechselseitiges Schalter der Frequenzen

This commit is contained in:
Dieter Lang 2026-08-02 09:09:50 +02:00
parent 4cc53facc6
commit b7ed142f00

56
main.go
View file

@ -5,8 +5,8 @@ import (
"fmt"
"log"
"os"
"sync"
"strings"
"sync"
"spannung/web" // Importiert Ihr eigenes web-Paket
@ -93,25 +93,33 @@ func main() {
log.Fatalf("ADS1115 #2 Init fehlgeschlagen: %v", err)
}
// 6. GPIO-Pins registrieren (ID 1 ist der 230V Hauptschalter am Raspberry Pi)
for i, r := range config.Relais {
// 6. Internen Software-Zustand für ALLE Relais VORAB auf AUS (false) setzen
for i := range config.Relais {
config.Relais[i].State = false
}
// 7. GPIO-Pins registrieren (ID 1 ist der 230V Hauptschalter am Raspberry Pi)
for _, r := range config.Relais {
if r.ID == 1 {
pin := gpioreg.ByName(r.GPIO)
if pin == nil {
log.Fatalf("GPIO-Pin %s existiert nicht", r.GPIO)
}
// Hauptschalter hardwareseitig sofort sicher ausschalten
if err := pin.Out(gpio.Low); err != nil {
log.Fatalf("Pin-Konfiguration für %s fehlgeschlagen: %v", r.GPIO, err)
}
relaisMap[r.ID] = pin
}
config.Relais[i].State = false
}
// 7. Beim Start alle USB-Relais initial auswerfen
updateUsbRelays()
// 8. SICHERHEITS-START: Alle USB-Relais initial zwingend ausschalten
// Wenn updateUsbRelaysStrict() fehlschlägt, bricht das Programm ab.
if err := updateUsbRelaysStrict(); err != nil {
log.Fatalf("[❌] KRITISCHER FEHLER: USB-Relais-Reset beim Start fehlgeschlagen! Programm gestoppt: %v", err)
}
// 8. Instanziierung des Webservers mit Übergabe der Callback-Funktionen
// 9. Instanziierung des Webservers mit Übergabe der Callback-Funktionen
server := web.NewServer(config.WebPort, readVoltageCallback, toggleRelaisCallback, getRelaisStateCallback, callbackGetVersion, getVoltNamesCallback)
fmt.Printf("Webserver gestartet auf Port %s\n", config.WebPort)
@ -170,7 +178,6 @@ func readVoltageCallback(channel int) float64 {
return 0.0
}
// Pin-Instanz erzeugen und auslesen (periph.io API Standard)
pin, err := targetDevice.PinForChannel(adsChannel, physic.Volt*4096/1000, 128*physic.Hertz, 0)
if err != nil {
fmt.Printf("Fehler beim Erzeugen des Pins für Kanal %v: %v\n", channel, err)
@ -216,8 +223,6 @@ func toggleRelaisCallback(id int) {
}
} else {
// ERWEITERUNG: Gegenseitige Verriegelung für USB-Relais
// Wenn das aktuelle USB-Relais auf EIN (true) geschaltet wurde,
// müssen alle ANDEREN USB-Relais (ID >= 2) zwangsweise auf AUS (false) gesetzt werden.
if config.Relais[i].State {
for j := range config.Relais {
if config.Relais[j].ID != id && config.Relais[j].ID >= 2 {
@ -227,29 +232,28 @@ func toggleRelaisCallback(id int) {
fmt.Printf("[🔄] Exklusiv-Modus: Relais ID %d aktiviert. Alle anderen USB-Relais wurden ausgeschaltet.\n", id)
}
// Hardware-Schaltung über Abacom USB-Karte via Schieberegister-Emulation aktualisieren
// Da updateUsbRelays() die gesamte Bitmaske liest, wird der neue Zustand sofort übertragen!
updateUsbRelays()
// Standard-Schaltvorgang (Fehler werfen im UI-Log, blockiert aber nicht den Server)
if err := updateUsbRelaysStrict(); err != nil {
fmt.Printf("[❌] Fehler beim Schalten der USB-Relais: %v\n", err)
}
}
break
}
}
}
// Hilfsfunktion: Schaltet die Abacom-Karte über exakte Schieberegister-Logik (Bit-Banging)
func updateUsbRelays() {
// Optimierte Hilfsfunktion: Schaltet die Abacom-Karte und gibt Fehler an den Aufrufer zurück
func updateUsbRelaysStrict() error {
fmt.Println("\n--- [USB ABACOM SCHALTVORGANG] ---")
ctx := gousb.NewContext()
defer ctx.Close()
dev, err := ctx.OpenDeviceWithVIDPID(0x1a86, 0x5512)
if err != nil {
fmt.Printf("[❌] USB-Fehler beim Öffnen des Geräts: %v\n", err)
return
return fmt.Errorf("USB-Fehler beim Öffnen des Geräts: %w", err)
}
if dev == nil {
fmt.Println("[❌] Hardware-Fehler: Abacom-Karte wurde am USB-Port nicht gefunden!")
return
return fmt.Errorf("Abacom-Karte wurde am USB-Port nicht gefunden")
}
defer dev.Close()
@ -257,22 +261,19 @@ func updateUsbRelays() {
cfg, err := dev.Config(1)
if err != nil {
fmt.Printf("[❌] Konfigurationsfehler: %v\n", err)
return
return fmt.Errorf("Konfigurationsfehler: %w", err)
}
defer cfg.Close()
intf, err := cfg.Interface(0, 0)
if err != nil {
fmt.Printf("[❌] Interface-Fehler: %v\n", err)
return
return fmt.Errorf("Interface-Fehler: %w", err)
}
defer intf.Close()
outEP, err := intf.OutEndpoint(2)
if err != nil {
fmt.Printf("[❌] Endpunkt-Fehler: %v\n", err)
return
return fmt.Errorf("Endpunkt-Fehler: %w", err)
}
// Bitmaske berechnen (ID 2 -> Bit 0 bis ID 9 -> Bit 7)
@ -308,11 +309,10 @@ func updateUsbRelays() {
fmt.Printf("[⚙️] Sende Bitmaske an Schieberegister: %08b\n", bitmask)
// --- Protokoll-Sequenz (Analog zu Python) ---
// --- Protokoll-Sequenz ---
sendOutput(0x00) // Latch initial auf Low halten
for i := 0; i < 8; i++ {
// MSB first (Bit 7 bis 0 prüfen)
if (bitmask & (1 << (7 - i))) != 0 {
sendOutput(DATA)
sendOutput(CLK | DATA)
@ -325,12 +325,12 @@ func updateUsbRelays() {
}
sendOutput(0x00) // Leitungen leeren
// Übernahme-Register per Latch freischalten
sendOutput(LATCH)
sendOutput(0x00)
fmt.Println("[✅] ERFOLG! Signal-Bytes an Schieberegister übergeben.")
fmt.Println("--- [USB DEBUG ENDE] ---\n")
return nil
}
// Callback: Wird vom Webserver aufgerufen, um den aktuellen UI-Status abzufragen