128 lines
2.8 KiB
Go
128 lines
2.8 KiB
Go
package services
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
type SensorValuesService struct {
|
|
ctx *Context
|
|
}
|
|
|
|
type sensorValue struct {
|
|
Timestamp int64 `json:"timestamp"`
|
|
Value float64 `json:"value"`
|
|
}
|
|
|
|
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)
|
|
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return res.LastInsertId()
|
|
}
|
|
|
|
func (s *SensorValuesService) GetList(sensorId int64, from int64, to int64) ([]sensorValue, error) {
|
|
return s.getValueItems(sensorId, from, to, getAutoSensorValuesInterval(from, to))
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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) {
|
|
values := make([]sensorValue, 0)
|
|
|
|
rows, err := s.getValueListQuery(sensorId, from, to, divide)
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return values, nil
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
|
|
for rows.Next() {
|
|
item := sensorValue{}
|
|
|
|
err := rows.Scan(&item.Timestamp, &item.Value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
values = append(values, item)
|
|
}
|
|
|
|
err = rows.Err()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return values, nil
|
|
}
|