112 lines
2.3 KiB
Go
112 lines
2.3 KiB
Go
package sensors
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log/slog"
|
|
"math/rand"
|
|
"nats-app/internal/broker"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type Simulator struct {
|
|
*broker.NATS
|
|
stopChannels map[string]chan bool
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func Start(nats *broker.NATS) *Simulator {
|
|
return &Simulator{
|
|
NATS: nats,
|
|
stopChannels: make(map[string]chan bool),
|
|
}
|
|
}
|
|
|
|
func (s *Simulator) SimulateSensor(sensor Sensor) {
|
|
s.mu.Lock()
|
|
stopChan := make(chan bool)
|
|
s.stopChannels[sensor.SensorID] = stopChan
|
|
s.mu.Unlock()
|
|
|
|
ticker := time.NewTicker(*sensor.SamplingInterval * time.Second)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-stopChan:
|
|
slog.Info("stopping simulator for sensor", "sensor_id", sensor.SensorID)
|
|
return
|
|
case <-ticker.C:
|
|
data := s.generateData(sensor)
|
|
|
|
if data.SensorID == "" {
|
|
slog.Warn("sensor data generation failed", "sensor_id", sensor.SensorID)
|
|
continue
|
|
}
|
|
|
|
payload, err := json.Marshal(data)
|
|
if err != nil {
|
|
slog.Error("failed to marshal sensor data", "error", err, "sensor_id", sensor.SensorID)
|
|
continue
|
|
}
|
|
|
|
subject := subjectSensorsData + sensor.SensorID
|
|
if err := s.Publish(subject, payload); err != nil {
|
|
slog.Error("failed to publish sensor data", "error", err, "subject", subject)
|
|
} else {
|
|
slog.Debug("sensor data published", "sensor_id", sensor.SensorID, "value", data.Value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Simulator) UpdateSensor(sensor Sensor) {
|
|
s.mu.Lock()
|
|
stopChan, exists := s.stopChannels[sensor.SensorID]
|
|
s.mu.Unlock()
|
|
|
|
if exists {
|
|
stopChan <- true
|
|
|
|
s.mu.Lock()
|
|
delete(s.stopChannels, sensor.SensorID)
|
|
s.mu.Unlock()
|
|
}
|
|
|
|
go s.SimulateSensor(sensor)
|
|
slog.Info("simulator updated for sensor", "sensor_id", sensor.SensorID, "new_interval", sensor.SamplingInterval)
|
|
}
|
|
|
|
func (s *Simulator) generateData(sensor Sensor) SensorData {
|
|
now := time.Now()
|
|
data := SensorData{
|
|
SensorID: sensor.SensorID,
|
|
Timestamp: &now,
|
|
}
|
|
|
|
if rand.Float64() < 0.05 {
|
|
return SensorData{}
|
|
}
|
|
|
|
var value float64
|
|
switch sensor.SensorType {
|
|
case Temperature:
|
|
value = -20 + rand.Float64()*100
|
|
case Humidity:
|
|
value = 10 + rand.Float64()*90
|
|
case CarbonDioxide:
|
|
value = 980 + rand.Float64()*60
|
|
case Pressure:
|
|
value = 950 + rand.Float64()*100
|
|
case Proximity:
|
|
value = rand.Float64() * 400
|
|
case Light:
|
|
value = rand.Float64() * 10000
|
|
default:
|
|
value = rand.Float64() * 100
|
|
}
|
|
data.Value = &value
|
|
|
|
return data
|
|
}
|