111 lines
3.1 KiB
Go
111 lines
3.1 KiB
Go
// Package server implementiert die gRPC-Dienste für das Remote-Shack-System.
|
|
package server
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
shack "remote-shack/api"
|
|
"remote-shack/internal/config"
|
|
)
|
|
|
|
// VerifiedModule speichert die geparste Hardware-Adresse und die zugehörigen Kanallabels.
|
|
type VerifiedModule struct {
|
|
Address int64
|
|
Labels []string
|
|
}
|
|
|
|
// TelemetryServer verwaltet die I2C-Abfragen einer dynamischen Anzahl von ADS1115-Platinen.
|
|
type TelemetryServer struct {
|
|
shack.UnimplementedTelemetryServiceServer
|
|
modules []VerifiedModule
|
|
}
|
|
|
|
// NewTelemetryServer initialisiert den Server und parst die I2C-Parameter sowie Labels aus der Konfiguration.
|
|
func NewTelemetryServer(cfg *config.ServerConfig) *TelemetryServer {
|
|
var verifiedMods []VerifiedModule
|
|
|
|
for i, mod := range cfg.Server.Modules {
|
|
if i >= 4 {
|
|
log.Println("[Hardware-Warnung] ADS1115 limitiert auf maximal 4 Platinen am Bus. Ignoriere weitere Einträge.")
|
|
break
|
|
}
|
|
|
|
addr, err := strconv.ParseInt(strings.TrimPrefix(mod.Address, "0x"), 16, 64)
|
|
if err != nil {
|
|
log.Printf("[Hardware-Fehler] Modul-Adresse '%s' ungültig: %v", mod.Address, err)
|
|
continue
|
|
}
|
|
|
|
if addr < 0 || addr > 127 {
|
|
log.Printf("[Hardware-Fehler] I2C-Adresse 0x%02x außerhalb des 7-Bit-Spektrums (0..127)", addr)
|
|
continue
|
|
}
|
|
|
|
// Sicherstellen, dass exakt 4 Labels vorliegen, notfalls mit Standardtext auffüllen
|
|
labels := mod.Labels
|
|
for len(labels) < 4 {
|
|
labels = append(labels, "Unbekannt")
|
|
}
|
|
|
|
verifiedMods = append(verifiedMods, VerifiedModule{
|
|
Address: addr,
|
|
Labels: labels,
|
|
})
|
|
log.Printf("[Hardware] Modul %d auf I2C 0x%02x mit Labels %v registriert.", i+1, addr, labels[:4])
|
|
}
|
|
|
|
return &TelemetryServer{modules: verifiedMods}
|
|
}
|
|
|
|
// StreamVoltages sendet fortlaufend die gemessenen Spannungen samt Konfigurationslabels an den Client.
|
|
func (s *TelemetryServer) StreamVoltages(req *shack.Empty, stream shack.TelemetryService_StreamVoltagesServer) error {
|
|
log.Printf("[Telemetrie] Volt-Monitor verbunden. Stream startet für %d Modul(e)...", len(s.modules))
|
|
|
|
ticker := time.NewTicker(500 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
for {
|
|
select {
|
|
case <-stream.Context().Done():
|
|
log.Println("[Telemetrie] Volt-Monitor-Client getrennt.")
|
|
return nil
|
|
case <-ticker.C:
|
|
chData := make(map[int32]*shack.ChannelReading)
|
|
var globalChannel int32 = 1
|
|
|
|
for _, mod := range s.modules {
|
|
var boardChannel int32
|
|
for boardChannel = 0; boardChannel < 4; boardChannel++ {
|
|
var simulatedVolt float32
|
|
switch globalChannel {
|
|
case 1:
|
|
simulatedVolt = 13.80 + (r.Float32() * 0.2 - 0.1)
|
|
case 2:
|
|
simulatedVolt = 5.02 + (r.Float32() * 0.06 - 0.03)
|
|
case 5:
|
|
simulatedVolt = 9.15 + (r.Float32() * 0.1 - 0.05)
|
|
default:
|
|
simulatedVolt = r.Float32() * 12.0
|
|
}
|
|
|
|
chData[globalChannel] = &shack.ChannelReading{
|
|
Voltage: simulatedVolt,
|
|
Label: mod.Labels[boardChannel],
|
|
}
|
|
globalChannel++
|
|
}
|
|
}
|
|
|
|
err := stream.Send(&shack.VoltageResponse{Channels: chData})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|