diff --git a/bootstrap/service.go b/bootstrap/service.go index 92b3f2a..0c0a476 100644 --- a/bootstrap/service.go +++ b/bootstrap/service.go @@ -25,6 +25,9 @@ const ( ServiceModeFSMoinitor ServiceModeHealthcheck ServiceModeTempMonitor + + tempChangeMonitorPeriod = 5 * time.Minute + ipChangeMonitorPeriod = 30 * time.Minute ) // Main adds standard handlers to the telega bot. @@ -53,13 +56,13 @@ func Main(runtime string, serviceMode byte) (status string, err error) { if (serviceMode & ServiceModePeriodic) == ServiceModePeriodic { // add periodic tasks log.Println("adding periodic tasks handlers") - bot.AddPeriodicTask(30*time.Minute, "Public IP Changed:", feed.PublicIP) + bot.AddPeriodicTask(ipChangeMonitorPeriod, "Public IP Changed:", feed.PublicIP) } if (serviceMode & ServiceModeTempMonitor) == ServiceModeTempMonitor { // add temperature change monitoring log.Println("adding temperature change monitoring") - bot.AddPeriodicTask(5*time.Minute, "Temperature changed:", feed.TemperatureMonitor) + bot.AddPeriodicTask(tempChangeMonitorPeriod, "Temperature changed:", feed.TemperatureMonitor) } if (serviceMode & ServiceModeFSMoinitor) == ServiceModeFSMoinitor { diff --git a/feed/temperature.go b/feed/temperature.go index f9a31d8..eec22b4 100644 --- a/feed/temperature.go +++ b/feed/temperature.go @@ -21,11 +21,13 @@ import ( ) const ( - sensorDevicePath = "/sys/bus/w1/devices/28-3c01d607ca0a/w1_slave" - errTemp int32 = -1000 - maxRetries = 10 - minRereshInterval = 5 * time.Second - monitoredTemperatureDiff = 0.5 + sensorDevicePath = "/sys/bus/w1/devices/28-3c01d607ca0a/w1_slave" + sensorDevicePathKey = "device-path" + sensorMinReadingIntervalPathKey = "min-read" + errTemp int32 = -1000 + maxRetries = 10 + minRereshInterval = 5 * time.Second + monitoredTemperatureDiff = 500 ) var ( @@ -88,9 +90,17 @@ func getTemperatureReading(fpath string) (int32, error) { } func getTemperatureReadingWithRetries(ctx context.Context, fpath string, retries int) (temperature int32, timestamp time.Time, err error) { + + var refreshInterval = func() time.Duration { + if p, ok := ctx.Value(sensorMinReadingIntervalPathKey).(time.Duration); ok { + return p + } + return minRereshInterval + } + // do not allow more frequent polls lastTimeMutex.RLock() - if time.Since(lastTime) < minRereshInterval { + if time.Since(lastTime) < refreshInterval() { defer lastTimeMutex.RUnlock() return atomic.LoadInt32(&lastTemp), lastTime, nil } @@ -131,11 +141,19 @@ func getTemperatureReadingWithRetries(ctx context.Context, fpath string, retries } // TemperatureMonitor 's for temp changes over the threshold -func TemperatureMonitor(ctx context.Context) (temprature string) { - v, _, err := getTemperatureReadingWithRetries(ctx, sensorDevicePath, 10) +func TemperatureMonitor(ctx context.Context) string { + var devicePath = func() string { + if p, ok := ctx.Value(sensorDevicePathKey).(string); ok { + return p + } + return sensorDevicePath + } + + v, _, err := getTemperatureReadingWithRetries(ctx, devicePath(), 10) if err != nil { return onError("error reading temperature", err) } + log.Println("temperature monitor: prev:", monitoredTemperature, "curr:", v) if math.Abs(float64(v-monitoredTemperature)) > monitoredTemperatureDiff { monitoredTemperature = v return fmt.Sprintf("%.1f ℃ 🌡", float32(v)/1000.0) diff --git a/feed/temperature_test.go b/feed/temperature_test.go index 3eee278..dd2f7c7 100644 --- a/feed/temperature_test.go +++ b/feed/temperature_test.go @@ -3,6 +3,7 @@ package feed import ( "context" "os" + "path" "strings" "testing" "time" @@ -67,3 +68,38 @@ func Test004_tempParseFilePersistent(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int32(29812), v) } + +func Test005_tempMonitorChanges(t *testing.T) { + + const ( + datapath = "temp_sensor_readings/" + t88 = "28_8c" + t95 = "29_5c" + t98 = "29_8c" + tr28 = "32_8c" + m108 = "minus_10_8_c" + m104 = "minus_10_4_c" + ) + + var noDelayCtx = func() context.Context { + return context.WithValue(context.Background(), sensorMinReadingIntervalPathKey, 1*time.Nanosecond) + } + + ctx := context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, t98)) + assert.True(t, strings.HasPrefix(TemperatureMonitor(ctx), "29.8")) + + ctx = context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, t95)) + assert.Empty(t, TemperatureMonitor(ctx)) + + ctx = context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, t88)) + assert.True(t, strings.HasPrefix(TemperatureMonitor(ctx), "28.8")) + + ctx = context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, tr28)) + assert.True(t, strings.HasPrefix(TemperatureMonitor(ctx), "32.8")) + + ctx = context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, m108)) + assert.True(t, strings.HasPrefix(TemperatureMonitor(ctx), "-10.8")) + + ctx = context.WithValue(noDelayCtx(), sensorDevicePathKey, path.Join(testDataDir, datapath, m104)) + assert.Empty(t, TemperatureMonitor(ctx)) +} diff --git a/telega/bot.go b/telega/bot.go index 66221f2..00d1495 100644 --- a/telega/bot.go +++ b/telega/bot.go @@ -316,8 +316,10 @@ func (b Bot) Run() (string, error) { func (b *Bot) processPeriodicTasks(chatIDs []int64) { b.periodicTaskCycle++ + log.Println("bot: processing periodic tasks") for _, h := range b.periodicTasks { - if b.periodicTaskCycle/h.interval == 0 { + log.Println("bot: executing periodic task", h.intro, b.periodicTaskCycle, h.interval, (b.periodicTaskCycle % h.interval)) + if b.periodicTaskCycle%h.interval == 0 { notificationMessageWrapper(b.ctx, h.intro, h.fn, b.bot, chatIDs) } } diff --git a/testdata/temp_sensor_readings/28_8c b/testdata/temp_sensor_readings/28_8c new file mode 100644 index 0000000..6301854 --- /dev/null +++ b/testdata/temp_sensor_readings/28_8c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=28812 diff --git a/testdata/temp_sensor_readings/29_5c b/testdata/temp_sensor_readings/29_5c new file mode 100644 index 0000000..a3002b6 --- /dev/null +++ b/testdata/temp_sensor_readings/29_5c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=29512 diff --git a/testdata/temp_sensor_readings/29_8c b/testdata/temp_sensor_readings/29_8c new file mode 100644 index 0000000..24a12d6 --- /dev/null +++ b/testdata/temp_sensor_readings/29_8c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=29812 diff --git a/testdata/temp_sensor_readings/32_8c b/testdata/temp_sensor_readings/32_8c new file mode 100644 index 0000000..b2d1a69 --- /dev/null +++ b/testdata/temp_sensor_readings/32_8c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=32812 diff --git a/testdata/temp_sensor_readings/minus_10_4_c b/testdata/temp_sensor_readings/minus_10_4_c new file mode 100644 index 0000000..b79f9a5 --- /dev/null +++ b/testdata/temp_sensor_readings/minus_10_4_c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=-10412 diff --git a/testdata/temp_sensor_readings/minus_10_8_c b/testdata/temp_sensor_readings/minus_10_8_c new file mode 100644 index 0000000..96c526a --- /dev/null +++ b/testdata/temp_sensor_readings/minus_10_8_c @@ -0,0 +1,2 @@ +dd 01 55 05 7f a5 a5 66 81 : crc=81 YES +dd 01 55 05 7f a5 a5 66 81 t=-10801