You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
62 lines
1.5 KiB
62 lines
1.5 KiB
package sensor
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"mqtt_washingmachine/internal/status"
|
|
)
|
|
|
|
// Sampler collects the latest valid message in each interval, independently of
|
|
// HTTP requests. Its zero value is ready to use; all methods are concurrency-safe.
|
|
type Sampler struct {
|
|
mu sync.Mutex
|
|
window status.Window
|
|
power float64
|
|
receivedAt time.Time
|
|
received bool
|
|
}
|
|
|
|
// Receive updates the pending measurement. Invalid payloads leave it untouched.
|
|
func (s *Sampler) Receive(payload []byte) error {
|
|
power, err := ParsePower(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.power, s.receivedAt, s.received = power, time.Now(), true
|
|
return nil
|
|
}
|
|
|
|
// Run records one sample per tick, then clears the received flag. An interval
|
|
// without valid messages is missing; a previous measurement is never reused.
|
|
// The caller supplies the ticker and runs only one Run loop per sampler.
|
|
func (s *Sampler) Run(ctx context.Context, ticks <-chan time.Time) {
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case _, ok := <-ticks:
|
|
if !ok {
|
|
return
|
|
}
|
|
s.mu.Lock()
|
|
sample := status.Sample{}
|
|
if s.received {
|
|
sample = status.Sample{Power: s.power, Valid: true}
|
|
}
|
|
s.window.Add(sample)
|
|
s.received = false
|
|
s.mu.Unlock()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Status returns an independent snapshot of the current window and its state.
|
|
func (s *Sampler) Status() status.Result {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
return status.Evaluate(s.window.Readings())
|
|
}
|
|
|