graphicek/server/services/sensor_values_service.go

134 lines
3.1 KiB
Go
Raw Normal View History

2022-08-13 23:33:50 +02:00
package services
import (
"database/sql"
2024-04-01 10:33:20 +02:00
"fmt"
"time"
)
2022-08-13 23:33:50 +02:00
type SensorValuesService struct {
ctx *Context
}
type sensorValue struct {
Timestamp int64 `json:"timestamp"`
Value float64 `json:"value"`
}
2022-08-28 11:56:03 +02:00
func (s *SensorValuesService) Push(sensorId int64, value float64) (int64, error) {
res, err := s.ctx.DB.Exec("INSERT INTO sensor_values (timestamp, sensor_id, value) VALUES (?, ?, ?)", time.Now().Unix(), sensorId, value)
2022-08-13 23:33:50 +02:00
if err != nil {
return 0, fmt.Errorf("failed to insert sensor value: %v", err)
}
_, err = s.ctx.DB.Exec("UPDATE sensors SET last_contact_at = ? WHERE id = ?", time.Now().Unix(), sensorId)
if err != nil {
return 0, fmt.Errorf("failed to update last_contact_at: %v", err)
2022-08-13 23:33:50 +02:00
}
return res.LastInsertId()
}
2022-08-28 11:56:03 +02:00
func (s *SensorValuesService) GetList(sensorId int64, from int64, to int64) ([]sensorValue, error) {
2022-09-04 09:42:12 +02:00
return s.getValueItems(sensorId, from, to, getAutoSensorValuesInterval(from, to))
2022-09-04 09:22:38 +02:00
}
func (s *SensorValuesService) GetLatest(sensorId int64, to int64) (*sensorValue, error) {
var value = sensorValue{}
row := s.ctx.DB.QueryRow("SELECT timestamp, value FROM sensor_values WHERE sensor_id = ? AND timestamp < ? ORDER BY timestamp DESC LIMIT 1", sensorId, to)
err := row.Scan(&value.Timestamp, &value.Value)
if err != nil {
return nil, err
}
return &value, nil
}
2024-04-01 10:33:20 +02:00
func (s *SensorValuesService) Cleanup(retentionInDays int64) error {
if retentionInDays <= 0 {
return fmt.Errorf("retentionInDays must be greater than 0")
}
_, err := s.ctx.DB.Exec("DELETE FROM sensor_values WHERE timestamp < ?", time.Now().Unix()-(retentionInDays*24*60*60))
if err != nil {
return err
}
return nil
}
2022-09-04 09:42:12 +02:00
func (s *SensorValuesService) getValueListQuery(sensorId int64, from int64, to int64, divide int64) (*sql.Rows, error) {
if divide == 1 {
return s.ctx.DB.Query("SELECT timestamp, value FROM sensor_values WHERE sensor_id = ? AND timestamp > ? AND timestamp < ? ORDER BY timestamp ASC", sensorId, from, to)
}
return s.ctx.DB.Query(
"SELECT (timestamp/?)*?, AVG(value) FROM sensor_values WHERE sensor_id = ? AND timestamp > ? AND timestamp < ? GROUP BY (timestamp/?) ORDER BY timestamp ASC",
divide,
divide,
sensorId,
from,
to,
divide,
)
}
func getAutoSensorValuesInterval(from int64, to int64) int64 {
diff := to - from
// 360 days -> 1 day interval
if diff > 360*24*60*60 {
return 24 * 60 * 60
}
// 160 days -> 1 hour interval
if diff > 160*24*60*60 {
return 60 * 60
}
// 80 days -> 10 minutes
if diff > 80*24*60*60 {
return 10 * 60
}
return 1
}
func (s *SensorValuesService) getValueItems(sensorId int64, from int64, to int64, divide int64) ([]sensorValue, error) {
2022-08-23 23:35:36 +02:00
values := make([]sensorValue, 0)
2022-08-13 23:33:50 +02:00
2022-09-04 09:42:12 +02:00
rows, err := s.getValueListQuery(sensorId, from, to, divide)
2022-08-13 23:33:50 +02:00
if err != nil {
if err == sql.ErrNoRows {
return values, nil
}
2022-08-13 23:33:50 +02:00
return nil, err
}
defer rows.Close()
for rows.Next() {
2022-09-04 09:22:38 +02:00
item := sensorValue{}
err := rows.Scan(&item.Timestamp, &item.Value)
2022-08-13 23:33:50 +02:00
if err != nil {
return nil, err
}
2022-09-04 09:22:38 +02:00
values = append(values, item)
2022-08-13 23:33:50 +02:00
}
err = rows.Err()
if err != nil {
return nil, err
}
return values, nil
}