fix(pkg/config): use storage endpoints
changes: - Only one storage endpoint can be defined. This consists of a URL which can be used to specify whether the data is to be stored in a file or in a database.
This commit is contained in:
parent
afe55b3d33
commit
dbef4f8241
@ -49,7 +49,7 @@ var rootCmd = &cobra.Command{
|
|||||||
DeviceName: hostname,
|
DeviceName: hostname,
|
||||||
CreationDate: t,
|
CreationDate: t,
|
||||||
},
|
},
|
||||||
Logfile: "/var/log/flucky/logfile.csv",
|
StorageEndpoint: "file:///var/log/flucky/logfile.csv",
|
||||||
}
|
}
|
||||||
|
|
||||||
err = config.Write(&cnf, configFile)
|
err = config.Write(&cnf, configFile)
|
||||||
|
@ -50,5 +50,5 @@ func InitCmd(cmd *cobra.Command, cnfFile *string, sversion *semver.Version) {
|
|||||||
cmd.AddCommand(daemonCmd)
|
cmd.AddCommand(daemonCmd)
|
||||||
daemonCmd.Flags().BoolVar(&compression, "compression", true, "Compress measured values")
|
daemonCmd.Flags().BoolVar(&compression, "compression", true, "Compress measured values")
|
||||||
daemonCmd.Flags().StringVar(&cleanCacheInterval, "clean-cache-interval", "5m", "Minute intervall to clean cache and write measured values into logfile")
|
daemonCmd.Flags().StringVar(&cleanCacheInterval, "clean-cache-interval", "5m", "Minute intervall to clean cache and write measured values into logfile")
|
||||||
daemonCmd.Flags().Float64Var(&round, "round", 0, "Round values. The value 0 deactivates the function")
|
daemonCmd.Flags().Float64Var(&round, "round", 0.5, "Round values. The value 0 deactivates the function")
|
||||||
}
|
}
|
||||||
|
52
cmd/db/db.go
52
cmd/db/db.go
@ -1,13 +1,7 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
|
||||||
database "github.com/go-flucky/flucky/pkg/storage/db"
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,33 +16,33 @@ var dbCmd = &cobra.Command{
|
|||||||
Short: "Operates with the configured database",
|
Short: "Operates with the configured database",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
// read configuration
|
// // read configuration
|
||||||
cnf, err := config.Read(*configFile)
|
// cnf, err := config.Read(*configFile)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Fatalln(err)
|
// log.Fatalln(err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
postgresDB, err := database.New(cnf.DatabaseSettings)
|
// postgresDB, err := database.New(cnf.DatabaseSettings)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
log.Fatalf("%v", err)
|
// log.Fatalf("%v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
ctx := context.Background()
|
// ctx := context.Background()
|
||||||
|
|
||||||
devices := []*types.Device{
|
// devices := []*types.Device{
|
||||||
&types.Device{
|
// &types.Device{
|
||||||
DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
// DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||||
DeviceName: "raspberr-pi",
|
// DeviceName: "raspberr-pi",
|
||||||
},
|
// },
|
||||||
&types.Device{
|
// &types.Device{
|
||||||
DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
// DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||||
DeviceName: "raspberr-pi",
|
// DeviceName: "raspberr-pi",
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
|
|
||||||
if err := postgresDB.InsertDevices(ctx, devices); err != nil {
|
// if err := postgresDB.InsertDevices(ctx, devices); err != nil {
|
||||||
log.Fatalln(err)
|
// log.Fatalln(err)
|
||||||
}
|
// }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package humidity
|
package humidity
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
"github.com/go-flucky/flucky/pkg/config"
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,19 +26,14 @@ var listTemperatureCmd = &cobra.Command{
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logfile := logfile.New(cnf.Logfile)
|
ctx := context.Background()
|
||||||
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
|
||||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
measuredValues, err := logfile.Read()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
@ -56,8 +56,12 @@ var readHumidityCmd = &cobra.Command{
|
|||||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||||
|
|
||||||
if logs {
|
if logs {
|
||||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
package pressure
|
package pressure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
"github.com/go-flucky/flucky/pkg/config"
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -25,19 +25,14 @@ var listTemperatureCmd = &cobra.Command{
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logfile := logfile.New(cnf.Logfile)
|
ctx := context.Background()
|
||||||
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
|
||||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
measuredValues, err := logfile.Read()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
@ -56,8 +56,12 @@ var readPressureCmd = &cobra.Command{
|
|||||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||||
|
|
||||||
if logs {
|
if logs {
|
||||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package temperature
|
package temperature
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
"github.com/go-flucky/flucky/pkg/config"
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,19 +26,14 @@ var listTemperatureCmd = &cobra.Command{
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logfile := logfile.New(cnf.Logfile)
|
ctx := context.Background()
|
||||||
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
|
||||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
measuredValues, err := logfile.Read()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/cli"
|
"github.com/go-flucky/flucky/pkg/cli"
|
||||||
@ -42,15 +41,9 @@ var readTemperatureCmd = &cobra.Command{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
|
||||||
if err := rgbled.Run(rgbLEDs); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
measuredValues, err := sensor.Read(ctx, sensors)
|
measuredValues, err := sensor.Read(ctx, sensors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rgbled.Error(rgbLEDs)
|
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,14 +53,16 @@ var readTemperatureCmd = &cobra.Command{
|
|||||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||||
|
|
||||||
if logs {
|
if logs {
|
||||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rgbled.Error(rgbLEDs)
|
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rgbled.Off(rgbLEDs)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ services:
|
|||||||
container_name: postgres
|
container_name: postgres
|
||||||
environment:
|
environment:
|
||||||
- PGTZ=${TZ}
|
- PGTZ=${TZ}
|
||||||
- POSTGRES_PASSWORD=${PG_PASSWORD}
|
- POSTGRES_DB=${POSTGRES_DB_NAME}
|
||||||
- POSTGRES_USER=${PG_USER}
|
- POSTGRES_USER=${POSTGRES_DB_USER}
|
||||||
- POSTGRES_DB=${PG_NAME}
|
- POSTGRES_PASSWORD=${POSTGRES_DB_PASS}
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
image: postgres:11.5-alpine
|
image: postgres:11.5-alpine
|
||||||
ports:
|
ports:
|
||||||
- ${PG_EXTERN_PORT}:${PG_INTERN_PORT}/tcp
|
- 5432:5432
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
@ -1,59 +1,600 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"net/url"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-flucky/flucky/pkg/internal/format"
|
||||||
|
"github.com/go-flucky/flucky/pkg/rgbled"
|
||||||
|
"github.com/go-flucky/flucky/pkg/sensor"
|
||||||
|
|
||||||
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
uuid "github.com/satori/go.uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
|
// Configuration of flucky
|
||||||
|
type Configuration struct {
|
||||||
// Read the configuration file
|
Device *types.Device `json:"device"`
|
||||||
func Read(configFile string) (*Configuration, error) {
|
StorageEndpoint string `json:"storage_endpoint"`
|
||||||
|
RGBLEDs []*types.RGBLED `json:"rgb_leds"`
|
||||||
fc := &Configuration{}
|
Sensors []*types.Sensor `json:"sensors"`
|
||||||
|
|
||||||
f, err := os.Open(configFile)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Can not open file %v: %v", configFile, err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
jsonDecoder := json.NewDecoder(f)
|
|
||||||
if err := jsonDecoder.Decode(&fc); err != nil {
|
|
||||||
return nil, fmt.Errorf("Can not unmarshal JSON: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fc, nil
|
// AddRGBLED add a new RGBLED
|
||||||
|
func (c *Configuration) AddRGBLED(rgbLED *types.RGBLED) error {
|
||||||
|
|
||||||
|
// check if RGBLEDID is a valid UUID string
|
||||||
|
if !validUUID.MatchString(rgbLED.RGBLEDID) {
|
||||||
|
rgbLED.RGBLEDID = uuid.NewV4().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if sensor name and sensor uuid already exists
|
||||||
|
for _, l := range c.RGBLEDs {
|
||||||
|
if l.RGBLEDName == rgbLED.RGBLEDName {
|
||||||
|
return fmt.Errorf("RGBLED %v already exists", rgbLED.RGBLEDName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.RGBLEDID == rgbLED.RGBLEDID {
|
||||||
|
return fmt.Errorf("RGBLED %v with UUID %v already exists", rgbLED.RGBLEDName, rgbLED.RGBLEDID)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the configuration into a file, specified by the configuration filepath
|
// check if sensor has a valid device id
|
||||||
func Write(cfg *Configuration, configFile string) error {
|
if rgbLED.DeviceID != c.Device.DeviceID {
|
||||||
|
rgbLED.DeviceID = c.Device.DeviceID
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
// overwrite creation date
|
||||||
configDir := filepath.Dir(configFile)
|
rgbLED.CreationDate = time.Now()
|
||||||
err := os.MkdirAll(configDir, os.ModeDir)
|
|
||||||
if err != nil {
|
// check
|
||||||
return fmt.Errorf("Can not create config directory %v: %v", configDir, err)
|
c.RGBLEDs = append(c.RGBLEDs, rgbLED)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSensor add a new sensor
|
||||||
|
func (c *Configuration) AddSensor(sensor *types.Sensor) error {
|
||||||
|
|
||||||
|
// check if sensorID is a valid UUID string
|
||||||
|
if !validUUID.MatchString(sensor.SensorID) {
|
||||||
|
sensor.SensorID = uuid.NewV4().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if sensor name and sensor uuid already exists
|
||||||
|
for _, s := range c.Sensors {
|
||||||
|
if s.SensorName == sensor.SensorName {
|
||||||
|
return fmt.Errorf("Sensor %v already exists", s.SensorName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.SensorID == sensor.SensorID {
|
||||||
|
return fmt.Errorf("Sensor %v with UUID %v already exists", s.SensorName, s.SensorID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.WireID != nil && sensor.WireID != nil {
|
||||||
|
if *s.WireID == *sensor.WireID {
|
||||||
|
return fmt.Errorf("Sensor with 1wire-id %v already exists as %v", *s.WireID, s.SensorName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Create(configFile)
|
// check if sensor has a valid device id
|
||||||
if err != nil {
|
if sensor.DeviceID != c.Device.DeviceID {
|
||||||
return fmt.Errorf("Can not write config file: %v", err)
|
sensor.DeviceID = c.Device.DeviceID
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(f)
|
// overwrite creation date
|
||||||
encoder.SetIndent("", " ")
|
sensor.CreationDate = format.FormatedTime()
|
||||||
err = encoder.Encode(cfg)
|
|
||||||
if err != nil {
|
//TODO: check if wire sensor exists in /dev/bus/w1/devices
|
||||||
return fmt.Errorf("Error in encoding struct to json: %v", err)
|
|
||||||
|
// check
|
||||||
|
c.Sensors = append(c.Sensors, sensor)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableRGBLED enables a rgb led by its name or its unique UUID
|
||||||
|
func (c *Configuration) DisableRGBLED(name string) error {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, rgbled := range c.RGBLEDs {
|
||||||
|
|
||||||
|
// disable sensor matched after name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
rgbled.RGBLEDName == name {
|
||||||
|
rgbled.RGBLEDEnabled = false
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable sensor matched by uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
rgbled.RGBLEDID == name {
|
||||||
|
rgbled.RGBLEDEnabled = false
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Can not found RGB-LED %v", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableSensor disables a sensor by its name or its unique UUID
|
||||||
|
func (c *Configuration) DisableSensor(name string) error {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, sensor := range c.Sensors {
|
||||||
|
|
||||||
|
// disable sensor matched after name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorName == name {
|
||||||
|
sensor.SensorEnabled = false
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove machted uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorID == name {
|
||||||
|
sensor.SensorEnabled = false
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Can not found sensor %v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableRGBLED enables a rgb led by its name or its unique UUID
|
||||||
|
func (c *Configuration) EnableRGBLED(name string) error {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, rgbled := range c.RGBLEDs {
|
||||||
|
|
||||||
|
// disable sensor matched after name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
rgbled.RGBLEDName == name {
|
||||||
|
rgbled.RGBLEDEnabled = true
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// disable sensor matched by uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
rgbled.RGBLEDID == name {
|
||||||
|
rgbled.RGBLEDEnabled = true
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Can not found RGB-LED %v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableSensor enables a sensor by its name or its unique UUID
|
||||||
|
func (c *Configuration) EnableSensor(name string) error {
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, sensor := range c.Sensors {
|
||||||
|
|
||||||
|
// disable sensor matched after name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorName == name {
|
||||||
|
sensor.SensorEnabled = true
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove machted uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorID == name {
|
||||||
|
sensor.SensorEnabled = true
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Can not found sensor %v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHumiditySensors returns a list of humidity sensors
|
||||||
|
func (c *Configuration) GetHumiditySensors(option Option) []sensor.Sensor {
|
||||||
|
sensors := c.getHumiditySensors()
|
||||||
|
|
||||||
|
cachedSensors := make([]*types.Sensor, 0)
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case ENABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
case DISABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if !sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
default:
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHumiditySensorsByName returns a list of humidity sensors by name,
|
||||||
|
// uuid or wire-id
|
||||||
|
func (c *Configuration) GetHumiditySensorsByName(names []string) []sensor.Sensor {
|
||||||
|
configHumiditySensors := make(map[string]*types.Sensor, 0)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
for _, s := range c.getHumiditySensors() {
|
||||||
|
switch name {
|
||||||
|
case s.SensorID:
|
||||||
|
configHumiditySensors[s.SensorID] = s
|
||||||
|
case s.SensorName:
|
||||||
|
configHumiditySensors[s.SensorID] = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
humiditySensors := make([]*types.Sensor, 0)
|
||||||
|
for _, cs := range configHumiditySensors {
|
||||||
|
humiditySensors = append(humiditySensors, cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.convertSensors(humiditySensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPressureSensors returns a list of pressure sensors
|
||||||
|
func (c *Configuration) GetPressureSensors(option Option) []sensor.Sensor {
|
||||||
|
sensors := c.getPressureSensors()
|
||||||
|
|
||||||
|
cachedSensors := make([]*types.Sensor, 0)
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case ENABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
case DISABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if !sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
default:
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPressureSensorsByName returns a list of pressure sensors by name,
|
||||||
|
// uuid or wire-id
|
||||||
|
func (c *Configuration) GetPressureSensorsByName(names []string) []sensor.Sensor {
|
||||||
|
configPressureSensors := make(map[string]*types.Sensor, 0)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
for _, s := range c.getPressureSensors() {
|
||||||
|
switch name {
|
||||||
|
case s.SensorID:
|
||||||
|
configPressureSensors[s.SensorID] = s
|
||||||
|
case s.SensorName:
|
||||||
|
configPressureSensors[s.SensorID] = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pressureSensors := make([]*types.Sensor, 0)
|
||||||
|
for _, cs := range configPressureSensors {
|
||||||
|
pressureSensors = append(pressureSensors, cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.convertSensors(pressureSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) GetRGBLEDs(option Option) []rgbled.RGBLED {
|
||||||
|
rgbLEDs := c.RGBLEDs
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case ENABLED:
|
||||||
|
for i, rgbLED := range c.RGBLEDs {
|
||||||
|
if !rgbLED.RGBLEDEnabled {
|
||||||
|
rgbLEDs = append(rgbLEDs[:i], rgbLEDs[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertRGBLEDs(rgbLEDs)
|
||||||
|
case DISABLED:
|
||||||
|
for i, rgbLED := range c.RGBLEDs {
|
||||||
|
if rgbLED.RGBLEDEnabled {
|
||||||
|
rgbLEDs = append(rgbLEDs[:i], rgbLEDs[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertRGBLEDs(rgbLEDs)
|
||||||
|
default:
|
||||||
|
return c.convertRGBLEDs(rgbLEDs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) GetRGBLEDsByName(names []string) []rgbled.RGBLED {
|
||||||
|
configRGBLEDs := make(map[string]*types.RGBLED, 0)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
for _, led := range c.RGBLEDs {
|
||||||
|
switch name {
|
||||||
|
case led.RGBLEDID:
|
||||||
|
configRGBLEDs[led.RGBLEDID] = led
|
||||||
|
case led.RGBLEDName:
|
||||||
|
configRGBLEDs[led.RGBLEDID] = led
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rgbLEDs := make([]*types.RGBLED, 0)
|
||||||
|
for _, rgbLED := range configRGBLEDs {
|
||||||
|
rgbLEDs = append(rgbLEDs, rgbLED)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.convertRGBLEDs(rgbLEDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSensors returns a list of humidity sensors
|
||||||
|
func (c *Configuration) GetSensors(option Option) []sensor.Sensor {
|
||||||
|
cachedSensors := make([]*types.Sensor, 0)
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case ENABLED:
|
||||||
|
for _, sensor := range c.Sensors {
|
||||||
|
if sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
case DISABLED:
|
||||||
|
for _, sensor := range c.Sensors {
|
||||||
|
if !sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
default:
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStorageEndpointURL returns a parsed storage endpoint url
|
||||||
|
func (c *Configuration) GetStorageEndpointURL() (*url.URL, error) {
|
||||||
|
storageEndpointURL, err := url.Parse(c.StorageEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Can not parse storage endpoint URL")
|
||||||
|
}
|
||||||
|
return storageEndpointURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTemperatureSensors returns a list of temperature sensors
|
||||||
|
func (c *Configuration) GetTemperatureSensors(option Option) []sensor.Sensor {
|
||||||
|
sensors := c.getTemperatureSensors()
|
||||||
|
|
||||||
|
cachedSensors := make([]*types.Sensor, 0)
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case ENABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
case DISABLED:
|
||||||
|
for _, sensor := range sensors {
|
||||||
|
if !sensor.SensorEnabled {
|
||||||
|
cachedSensors = append(cachedSensors, sensor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
default:
|
||||||
|
return c.convertSensors(cachedSensors)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTemperatureSensorsByName returns a list of temperature sensors by name,
|
||||||
|
// uuid or wire-id
|
||||||
|
func (c *Configuration) GetTemperatureSensorsByName(names []string) []sensor.Sensor {
|
||||||
|
configTemperatureSensors := make(map[string]*types.Sensor, 0)
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
for _, s := range c.getTemperatureSensors() {
|
||||||
|
switch name {
|
||||||
|
case s.SensorID:
|
||||||
|
configTemperatureSensors[s.SensorID] = s
|
||||||
|
case s.SensorName:
|
||||||
|
configTemperatureSensors[s.SensorID] = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
temperatureSensors := make([]*types.Sensor, 0)
|
||||||
|
for _, cs := range configTemperatureSensors {
|
||||||
|
temperatureSensors = append(temperatureSensors, cs)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.convertSensors(temperatureSensors)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveRGBLED deletes a LED by its name or its unique UUID
|
||||||
|
func (c *Configuration) RemoveRGBLED(name string) error {
|
||||||
|
for i, rgbLED := range c.RGBLEDs {
|
||||||
|
// remove machted name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
rgbLED.RGBLEDName == name {
|
||||||
|
c.RGBLEDs = append(c.RGBLEDs[:i], c.RGBLEDs[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// remove machted uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
rgbLED.RGBLEDID == name {
|
||||||
|
c.RGBLEDs = append(c.RGBLEDs[:i], c.RGBLEDs[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Can not find RGBLED %v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveSensor deletes a sensor by its name or its unique UUID
|
||||||
|
func (c *Configuration) RemoveSensor(name string) error {
|
||||||
|
for i, sensor := range c.Sensors {
|
||||||
|
// remove machted name
|
||||||
|
if !validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorName == name {
|
||||||
|
c.Sensors = append(c.Sensors[:i], c.Sensors[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// remove machted uuid
|
||||||
|
if validUUID.MatchString(name) &&
|
||||||
|
sensor.SensorID == name {
|
||||||
|
c.Sensors = append(c.Sensors[:i], c.Sensors[i+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Can not find sensor %v", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameRGBLED renames a sensor identified by the name or the UUID
|
||||||
|
func (c *Configuration) RenameRGBLED(oldName, newName string) error {
|
||||||
|
for _, rgbled := range c.RGBLEDs {
|
||||||
|
if rgbled.RGBLEDName == oldName ||
|
||||||
|
rgbled.RGBLEDID == oldName {
|
||||||
|
rgbled.RGBLEDName = newName
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Could not find rgb-led %v to replace into with %v", oldName, newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameSensor renames a sensor identified by the name or the UUID
|
||||||
|
func (c *Configuration) RenameSensor(oldName, newName string) error {
|
||||||
|
for _, sensor := range c.Sensors {
|
||||||
|
if sensor.SensorName == oldName ||
|
||||||
|
sensor.SensorID == oldName {
|
||||||
|
sensor.SensorName = newName
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("Could not find remote %v to replace into with %v", oldName, newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) SetStorageEndpoint(storageEndpoint string) error {
|
||||||
|
storageEndpointURL, err := url.Parse(storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Can not prase sorage endpoint url: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
supportedStorageEndpoints := []string{"file", "postgres"}
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, supportedStorageEndpoint := range supportedStorageEndpoints {
|
||||||
|
if supportedStorageEndpoint == storageEndpointURL.Scheme {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Storage endpoint scheme not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.StorageEndpoint = storageEndpointURL.String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) convertSensors(sensors []*types.Sensor) []sensor.Sensor {
|
||||||
|
cachedSensors := make([]sensor.Sensor, 0)
|
||||||
|
|
||||||
|
for _, s := range sensors {
|
||||||
|
switch s.SensorModel {
|
||||||
|
case types.BME280:
|
||||||
|
cachedSensors = append(cachedSensors, &sensor.BME280{
|
||||||
|
Sensor: s,
|
||||||
|
})
|
||||||
|
case types.DHT11:
|
||||||
|
cachedSensors = append(cachedSensors, &sensor.DHT11{
|
||||||
|
Sensor: s,
|
||||||
|
})
|
||||||
|
case types.DHT22:
|
||||||
|
cachedSensors = append(cachedSensors, &sensor.DHT22{
|
||||||
|
Sensor: s,
|
||||||
|
})
|
||||||
|
case types.DS18B20:
|
||||||
|
cachedSensors = append(cachedSensors, &sensor.DS18B20{
|
||||||
|
Sensor: s,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cachedSensors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) convertRGBLEDs(rgbLEDs []*types.RGBLED) []rgbled.RGBLED {
|
||||||
|
leds := make([]rgbled.RGBLED, 0)
|
||||||
|
|
||||||
|
for _, rgbLED := range rgbLEDs {
|
||||||
|
leds = append(leds, &rgbled.DefaultRGBLED{
|
||||||
|
RGBLED: rgbLED,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return leds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) getHumiditySensors() []*types.Sensor {
|
||||||
|
humiditySensors := make([]*types.Sensor, 0)
|
||||||
|
for _, s := range c.Sensors {
|
||||||
|
if _, ok := humiditySensorModels[s.SensorModel]; ok {
|
||||||
|
humiditySensors = append(humiditySensors, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return humiditySensors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) getPressureSensors() []*types.Sensor {
|
||||||
|
pressureSensors := make([]*types.Sensor, 0)
|
||||||
|
for _, s := range c.Sensors {
|
||||||
|
if _, ok := pressureSensorModels[s.SensorModel]; ok {
|
||||||
|
pressureSensors = append(pressureSensors, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pressureSensors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) getTemperatureSensors() []*types.Sensor {
|
||||||
|
temperatureSensors := make([]*types.Sensor, 0)
|
||||||
|
for _, s := range c.Sensors {
|
||||||
|
if _, ok := temperatureSensorModels[s.SensorModel]; ok {
|
||||||
|
temperatureSensors = append(temperatureSensors, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temperatureSensors
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
type DatabaseSettings struct {
|
|
||||||
Vendor DatabaseVendor `json:"vendor"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Port string `json:"port"`
|
|
||||||
Database string `json:"database"`
|
|
||||||
User string `json:"user"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DatabaseVendor string
|
|
||||||
|
|
||||||
func (dv DatabaseVendor) String() string {
|
|
||||||
return string(dv)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
VendorPostgreSQL DatabaseVendor = "postgres"
|
|
||||||
VendorOracle = "oracle"
|
|
||||||
)
|
|
@ -1,594 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/internal/format"
|
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
|
||||||
"github.com/go-flucky/flucky/pkg/sensor"
|
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
|
||||||
uuid "github.com/satori/go.uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
var humiditySensorModels = map[types.SensorModel]types.SensorModel{
|
|
||||||
types.BME280: types.BME280,
|
|
||||||
types.DHT11: types.DHT11,
|
|
||||||
types.DHT22: types.DHT22,
|
|
||||||
}
|
|
||||||
|
|
||||||
var pressureSensorModels = map[types.SensorModel]types.SensorModel{
|
|
||||||
types.BME280: types.BME280,
|
|
||||||
}
|
|
||||||
|
|
||||||
var temperatureSensorModels = map[types.SensorModel]types.SensorModel{
|
|
||||||
types.BME280: types.BME280,
|
|
||||||
types.DHT11: types.DHT11,
|
|
||||||
types.DHT22: types.DHT22,
|
|
||||||
types.DS18B20: types.DS18B20,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration of flucky
|
|
||||||
type Configuration struct {
|
|
||||||
DatabaseSettings *DatabaseSettings `json:"database_settings"`
|
|
||||||
Device *types.Device `json:"device"`
|
|
||||||
Logfile string `json:"logfile" xml:"logfile"`
|
|
||||||
RGBLEDs []*types.RGBLED `json:"rgb_leds"`
|
|
||||||
Sensors []*types.Sensor `json:"sensors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddRGBLED add a new RGBLED
|
|
||||||
func (c *Configuration) AddRGBLED(rgbLED *types.RGBLED) error {
|
|
||||||
|
|
||||||
// check if RGBLEDID is a valid UUID string
|
|
||||||
if !validUUID.MatchString(rgbLED.RGBLEDID) {
|
|
||||||
rgbLED.RGBLEDID = uuid.NewV4().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if sensor name and sensor uuid already exists
|
|
||||||
for _, l := range c.RGBLEDs {
|
|
||||||
if l.RGBLEDName == rgbLED.RGBLEDName {
|
|
||||||
return fmt.Errorf("RGBLED %v already exists", rgbLED.RGBLEDName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.RGBLEDID == rgbLED.RGBLEDID {
|
|
||||||
return fmt.Errorf("RGBLED %v with UUID %v already exists", rgbLED.RGBLEDName, rgbLED.RGBLEDID)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if sensor has a valid device id
|
|
||||||
if rgbLED.DeviceID != c.Device.DeviceID {
|
|
||||||
rgbLED.DeviceID = c.Device.DeviceID
|
|
||||||
}
|
|
||||||
|
|
||||||
// overwrite creation date
|
|
||||||
rgbLED.CreationDate = time.Now()
|
|
||||||
|
|
||||||
// check
|
|
||||||
c.RGBLEDs = append(c.RGBLEDs, rgbLED)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSensor add a new sensor
|
|
||||||
func (c *Configuration) AddSensor(sensor *types.Sensor) error {
|
|
||||||
|
|
||||||
// check if sensorID is a valid UUID string
|
|
||||||
if !validUUID.MatchString(sensor.SensorID) {
|
|
||||||
sensor.SensorID = uuid.NewV4().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if sensor name and sensor uuid already exists
|
|
||||||
for _, s := range c.Sensors {
|
|
||||||
if s.SensorName == sensor.SensorName {
|
|
||||||
return fmt.Errorf("Sensor %v already exists", s.SensorName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.SensorID == sensor.SensorID {
|
|
||||||
return fmt.Errorf("Sensor %v with UUID %v already exists", s.SensorName, s.SensorID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sensor.WireID != nil {
|
|
||||||
if *s.WireID == *sensor.WireID {
|
|
||||||
return fmt.Errorf("Sensor with 1wire-id %v already exists as %v", *s.WireID, s.SensorName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if sensor has a valid device id
|
|
||||||
if sensor.DeviceID != c.Device.DeviceID {
|
|
||||||
sensor.DeviceID = c.Device.DeviceID
|
|
||||||
}
|
|
||||||
|
|
||||||
// overwrite creation date
|
|
||||||
sensor.CreationDate = format.FormatedTime()
|
|
||||||
|
|
||||||
//TODO: check if wire sensor exists in /dev/bus/w1/devices
|
|
||||||
|
|
||||||
// check
|
|
||||||
c.Sensors = append(c.Sensors, sensor)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableRGBLED enables a rgb led by its name or its unique UUID
|
|
||||||
func (c *Configuration) DisableRGBLED(name string) error {
|
|
||||||
found := false
|
|
||||||
|
|
||||||
for _, rgbled := range c.RGBLEDs {
|
|
||||||
|
|
||||||
// disable sensor matched after name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
rgbled.RGBLEDName == name {
|
|
||||||
rgbled.RGBLEDEnabled = false
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable sensor matched by uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
rgbled.RGBLEDID == name {
|
|
||||||
rgbled.RGBLEDEnabled = false
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("Can not found RGB-LED %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableSensor disables a sensor by its name or its unique UUID
|
|
||||||
func (c *Configuration) DisableSensor(name string) error {
|
|
||||||
found := false
|
|
||||||
|
|
||||||
for _, sensor := range c.Sensors {
|
|
||||||
|
|
||||||
// disable sensor matched after name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorName == name {
|
|
||||||
sensor.SensorEnabled = false
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove machted uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorID == name {
|
|
||||||
sensor.SensorEnabled = false
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("Can not found sensor %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableRGBLED enables a rgb led by its name or its unique UUID
|
|
||||||
func (c *Configuration) EnableRGBLED(name string) error {
|
|
||||||
found := false
|
|
||||||
|
|
||||||
for _, rgbled := range c.RGBLEDs {
|
|
||||||
|
|
||||||
// disable sensor matched after name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
rgbled.RGBLEDName == name {
|
|
||||||
rgbled.RGBLEDEnabled = true
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable sensor matched by uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
rgbled.RGBLEDID == name {
|
|
||||||
rgbled.RGBLEDEnabled = true
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("Can not found RGB-LED %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableSensor enables a sensor by its name or its unique UUID
|
|
||||||
func (c *Configuration) EnableSensor(name string) error {
|
|
||||||
found := false
|
|
||||||
|
|
||||||
for _, sensor := range c.Sensors {
|
|
||||||
|
|
||||||
// disable sensor matched after name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorName == name {
|
|
||||||
sensor.SensorEnabled = true
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove machted uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorID == name {
|
|
||||||
sensor.SensorEnabled = true
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("Can not found sensor %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHumiditySensors returns a list of humidity sensors
|
|
||||||
func (c *Configuration) GetHumiditySensors(option Option) []sensor.Sensor {
|
|
||||||
sensors := c.getHumiditySensors()
|
|
||||||
|
|
||||||
cachedSensors := make([]*types.Sensor, 0)
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case ENABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
case DISABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if !sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
default:
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHumiditySensorsByName returns a list of humidity sensors by name,
|
|
||||||
// uuid or wire-id
|
|
||||||
func (c *Configuration) GetHumiditySensorsByName(names []string) []sensor.Sensor {
|
|
||||||
configHumiditySensors := make(map[string]*types.Sensor, 0)
|
|
||||||
|
|
||||||
for _, name := range names {
|
|
||||||
for _, s := range c.getHumiditySensors() {
|
|
||||||
switch name {
|
|
||||||
case s.SensorID:
|
|
||||||
configHumiditySensors[s.SensorID] = s
|
|
||||||
case s.SensorName:
|
|
||||||
configHumiditySensors[s.SensorID] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
humiditySensors := make([]*types.Sensor, 0)
|
|
||||||
for _, cs := range configHumiditySensors {
|
|
||||||
humiditySensors = append(humiditySensors, cs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.convertSensors(humiditySensors)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPressureSensors returns a list of pressure sensors
|
|
||||||
func (c *Configuration) GetPressureSensors(option Option) []sensor.Sensor {
|
|
||||||
sensors := c.getPressureSensors()
|
|
||||||
|
|
||||||
cachedSensors := make([]*types.Sensor, 0)
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case ENABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
case DISABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if !sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
default:
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPressureSensorsByName returns a list of pressure sensors by name,
|
|
||||||
// uuid or wire-id
|
|
||||||
func (c *Configuration) GetPressureSensorsByName(names []string) []sensor.Sensor {
|
|
||||||
configPressureSensors := make(map[string]*types.Sensor, 0)
|
|
||||||
|
|
||||||
for _, name := range names {
|
|
||||||
for _, s := range c.getPressureSensors() {
|
|
||||||
switch name {
|
|
||||||
case s.SensorID:
|
|
||||||
configPressureSensors[s.SensorID] = s
|
|
||||||
case s.SensorName:
|
|
||||||
configPressureSensors[s.SensorID] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pressureSensors := make([]*types.Sensor, 0)
|
|
||||||
for _, cs := range configPressureSensors {
|
|
||||||
pressureSensors = append(pressureSensors, cs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.convertSensors(pressureSensors)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) GetRGBLEDs(option Option) []rgbled.RGBLED {
|
|
||||||
rgbLEDs := c.RGBLEDs
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case ENABLED:
|
|
||||||
for i, rgbLED := range c.RGBLEDs {
|
|
||||||
if !rgbLED.RGBLEDEnabled {
|
|
||||||
rgbLEDs = append(rgbLEDs[:i], rgbLEDs[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertRGBLEDs(rgbLEDs)
|
|
||||||
case DISABLED:
|
|
||||||
for i, rgbLED := range c.RGBLEDs {
|
|
||||||
if rgbLED.RGBLEDEnabled {
|
|
||||||
rgbLEDs = append(rgbLEDs[:i], rgbLEDs[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertRGBLEDs(rgbLEDs)
|
|
||||||
default:
|
|
||||||
return c.convertRGBLEDs(rgbLEDs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) GetRGBLEDsByName(names []string) []rgbled.RGBLED {
|
|
||||||
configRGBLEDs := make(map[string]*types.RGBLED, 0)
|
|
||||||
|
|
||||||
for _, name := range names {
|
|
||||||
for _, led := range c.RGBLEDs {
|
|
||||||
switch name {
|
|
||||||
case led.RGBLEDID:
|
|
||||||
configRGBLEDs[led.RGBLEDID] = led
|
|
||||||
case led.RGBLEDName:
|
|
||||||
configRGBLEDs[led.RGBLEDID] = led
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbLEDs := make([]*types.RGBLED, 0)
|
|
||||||
for _, rgbLED := range configRGBLEDs {
|
|
||||||
rgbLEDs = append(rgbLEDs, rgbLED)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.convertRGBLEDs(rgbLEDs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSensors returns a list of humidity sensors
|
|
||||||
func (c *Configuration) GetSensors(option Option) []sensor.Sensor {
|
|
||||||
cachedSensors := make([]*types.Sensor, 0)
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case ENABLED:
|
|
||||||
for _, sensor := range c.Sensors {
|
|
||||||
if sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
case DISABLED:
|
|
||||||
for _, sensor := range c.Sensors {
|
|
||||||
if !sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
default:
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTemperatureSensors returns a list of temperature sensors
|
|
||||||
func (c *Configuration) GetTemperatureSensors(option Option) []sensor.Sensor {
|
|
||||||
sensors := c.getTemperatureSensors()
|
|
||||||
|
|
||||||
cachedSensors := make([]*types.Sensor, 0)
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case ENABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
case DISABLED:
|
|
||||||
for _, sensor := range sensors {
|
|
||||||
if !sensor.SensorEnabled {
|
|
||||||
cachedSensors = append(cachedSensors, sensor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
default:
|
|
||||||
return c.convertSensors(cachedSensors)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetTemperatureSensorsByName returns a list of temperature sensors by name,
|
|
||||||
// uuid or wire-id
|
|
||||||
func (c *Configuration) GetTemperatureSensorsByName(names []string) []sensor.Sensor {
|
|
||||||
configTemperatureSensors := make(map[string]*types.Sensor, 0)
|
|
||||||
|
|
||||||
for _, name := range names {
|
|
||||||
for _, s := range c.getTemperatureSensors() {
|
|
||||||
switch name {
|
|
||||||
case s.SensorID:
|
|
||||||
configTemperatureSensors[s.SensorID] = s
|
|
||||||
case s.SensorName:
|
|
||||||
configTemperatureSensors[s.SensorID] = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
temperatureSensors := make([]*types.Sensor, 0)
|
|
||||||
for _, cs := range configTemperatureSensors {
|
|
||||||
temperatureSensors = append(temperatureSensors, cs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.convertSensors(temperatureSensors)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDatabaseSettings remove data base setting informations
|
|
||||||
func (c *Configuration) RemoveDatabaseSettings() {
|
|
||||||
c.DatabaseSettings = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveRGBLED deletes a LED by its name or its unique UUID
|
|
||||||
func (c *Configuration) RemoveRGBLED(name string) error {
|
|
||||||
for i, rgbLED := range c.RGBLEDs {
|
|
||||||
// remove machted name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
rgbLED.RGBLEDName == name {
|
|
||||||
c.RGBLEDs = append(c.RGBLEDs[:i], c.RGBLEDs[i+1:]...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// remove machted uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
rgbLED.RGBLEDID == name {
|
|
||||||
c.RGBLEDs = append(c.RGBLEDs[:i], c.RGBLEDs[i+1:]...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Can not find RGBLED %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveSensor deletes a sensor by its name or its unique UUID
|
|
||||||
func (c *Configuration) RemoveSensor(name string) error {
|
|
||||||
for i, sensor := range c.Sensors {
|
|
||||||
// remove machted name
|
|
||||||
if !validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorName == name {
|
|
||||||
c.Sensors = append(c.Sensors[:i], c.Sensors[i+1:]...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// remove machted uuid
|
|
||||||
if validUUID.MatchString(name) &&
|
|
||||||
sensor.SensorID == name {
|
|
||||||
c.Sensors = append(c.Sensors[:i], c.Sensors[i+1:]...)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Can not find sensor %v", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenameRGBLED renames a sensor identified by the name or the UUID
|
|
||||||
func (c *Configuration) RenameRGBLED(oldName, newName string) error {
|
|
||||||
for _, rgbled := range c.RGBLEDs {
|
|
||||||
if rgbled.RGBLEDName == oldName ||
|
|
||||||
rgbled.RGBLEDID == oldName {
|
|
||||||
rgbled.RGBLEDName = newName
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Could not find rgb-led %v to replace into with %v", oldName, newName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenameSensor renames a sensor identified by the name or the UUID
|
|
||||||
func (c *Configuration) RenameSensor(oldName, newName string) error {
|
|
||||||
for _, sensor := range c.Sensors {
|
|
||||||
if sensor.SensorName == oldName ||
|
|
||||||
sensor.SensorID == oldName {
|
|
||||||
sensor.SensorName = newName
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("Could not find remote %v to replace into with %v", oldName, newName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDatabaseSettings set database setting informations
|
|
||||||
func (c *Configuration) SetDatabaseSettings(databaseSettings *DatabaseSettings) {
|
|
||||||
c.DatabaseSettings = databaseSettings
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) convertSensors(sensors []*types.Sensor) []sensor.Sensor {
|
|
||||||
cachedSensors := make([]sensor.Sensor, 0)
|
|
||||||
|
|
||||||
for _, s := range sensors {
|
|
||||||
switch s.SensorModel {
|
|
||||||
case types.BME280:
|
|
||||||
cachedSensors = append(cachedSensors, &sensor.BME280{
|
|
||||||
Sensor: s,
|
|
||||||
})
|
|
||||||
case types.DHT11:
|
|
||||||
cachedSensors = append(cachedSensors, &sensor.DHT11{
|
|
||||||
Sensor: s,
|
|
||||||
})
|
|
||||||
case types.DHT22:
|
|
||||||
cachedSensors = append(cachedSensors, &sensor.DHT22{
|
|
||||||
Sensor: s,
|
|
||||||
})
|
|
||||||
case types.DS18B20:
|
|
||||||
cachedSensors = append(cachedSensors, &sensor.DS18B20{
|
|
||||||
Sensor: s,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cachedSensors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) convertRGBLEDs(rgbLEDs []*types.RGBLED) []rgbled.RGBLED {
|
|
||||||
leds := make([]rgbled.RGBLED, 0)
|
|
||||||
|
|
||||||
for _, rgbLED := range rgbLEDs {
|
|
||||||
leds = append(leds, &rgbled.DefaultRGBLED{
|
|
||||||
RGBLED: rgbLED,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return leds
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) getHumiditySensors() []*types.Sensor {
|
|
||||||
humiditySensors := make([]*types.Sensor, 0)
|
|
||||||
for _, s := range c.Sensors {
|
|
||||||
if _, ok := humiditySensorModels[s.SensorModel]; ok {
|
|
||||||
humiditySensors = append(humiditySensors, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return humiditySensors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) getPressureSensors() []*types.Sensor {
|
|
||||||
pressureSensors := make([]*types.Sensor, 0)
|
|
||||||
for _, s := range c.Sensors {
|
|
||||||
if _, ok := pressureSensorModels[s.SensorModel]; ok {
|
|
||||||
pressureSensors = append(pressureSensors, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pressureSensors
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) getTemperatureSensors() []*types.Sensor {
|
|
||||||
temperatureSensors := make([]*types.Sensor, 0)
|
|
||||||
for _, s := range c.Sensors {
|
|
||||||
if _, ok := temperatureSensorModels[s.SensorModel]; ok {
|
|
||||||
temperatureSensors = append(temperatureSensors, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return temperatureSensors
|
|
||||||
}
|
|
59
pkg/config/io.go
Normal file
59
pkg/config/io.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var validUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
|
||||||
|
|
||||||
|
// Read the configuration file
|
||||||
|
func Read(configFile string) (*Configuration, error) {
|
||||||
|
|
||||||
|
fc := &Configuration{}
|
||||||
|
|
||||||
|
f, err := os.Open(configFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Can not open file %v: %v", configFile, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
jsonDecoder := json.NewDecoder(f)
|
||||||
|
if err := jsonDecoder.Decode(&fc); err != nil {
|
||||||
|
return nil, fmt.Errorf("Can not unmarshal JSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fc, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the configuration into a file, specified by the configuration filepath
|
||||||
|
func Write(cfg *Configuration, configFile string) error {
|
||||||
|
|
||||||
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||||
|
configDir := filepath.Dir(configFile)
|
||||||
|
err := os.MkdirAll(configDir, os.ModeDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Can not create config directory %v: %v", configDir, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(configFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Can not write config file: %v", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(f)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
err = encoder.Encode(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error in encoding struct to json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
22
pkg/config/sensors.go
Normal file
22
pkg/config/sensors.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
|
var (
|
||||||
|
humiditySensorModels = map[types.SensorModel]types.SensorModel{
|
||||||
|
types.BME280: types.BME280,
|
||||||
|
types.DHT11: types.DHT11,
|
||||||
|
types.DHT22: types.DHT22,
|
||||||
|
}
|
||||||
|
|
||||||
|
pressureSensorModels = map[types.SensorModel]types.SensorModel{
|
||||||
|
types.BME280: types.BME280,
|
||||||
|
}
|
||||||
|
|
||||||
|
temperatureSensorModels = map[types.SensorModel]types.SensorModel{
|
||||||
|
types.BME280: types.BME280,
|
||||||
|
types.DHT11: types.DHT11,
|
||||||
|
types.DHT22: types.DHT22,
|
||||||
|
types.DS18B20: types.DS18B20,
|
||||||
|
}
|
||||||
|
)
|
@ -9,11 +9,9 @@ import (
|
|||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
"github.com/go-flucky/flucky/pkg/config"
|
||||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
|
||||||
"github.com/go-flucky/flucky/pkg/sensor"
|
"github.com/go-flucky/flucky/pkg/sensor"
|
||||||
"github.com/go-flucky/flucky/pkg/storage"
|
"github.com/go-flucky/flucky/pkg/storage"
|
||||||
"github.com/go-flucky/flucky/pkg/storage/db"
|
"github.com/go-flucky/flucky/pkg/storage/db"
|
||||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
"github.com/volker-raschek/go-logger/pkg/logger"
|
"github.com/volker-raschek/go-logger/pkg/logger"
|
||||||
)
|
)
|
||||||
@ -25,12 +23,8 @@ var (
|
|||||||
postgresUser = "postgres"
|
postgresUser = "postgres"
|
||||||
postgresPassword = "postgres"
|
postgresPassword = "postgres"
|
||||||
|
|
||||||
flogger logger.Logger
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flogger = logger.NewSilentLogger()
|
flogger = logger.NewSilentLogger()
|
||||||
}
|
)
|
||||||
|
|
||||||
func SetLogger(logger logger.Logger) {
|
func SetLogger(logger logger.Logger) {
|
||||||
flogger = logger
|
flogger = logger
|
||||||
@ -39,69 +33,63 @@ func SetLogger(logger logger.Logger) {
|
|||||||
// Start the daemon
|
// Start the daemon
|
||||||
func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, version *semver.Version) {
|
func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, version *semver.Version) {
|
||||||
|
|
||||||
|
// Context
|
||||||
|
parentCtx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(parentCtx)
|
||||||
|
|
||||||
|
// Ticker
|
||||||
|
// saveTicker := time.Tick(cleanCacheInterval)
|
||||||
|
|
||||||
|
// channels
|
||||||
|
debugChannel := make(chan string, 0)
|
||||||
|
infoChannel := make(chan string, 0)
|
||||||
|
warnChannel := make(chan string, 0)
|
||||||
|
errorChannel := make(chan error, 0)
|
||||||
|
fatalChannel := make(chan error, 1)
|
||||||
|
interruptChannel := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(interruptChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||||
|
measuredValueChannel := make(chan *types.MeasuredValue, 0)
|
||||||
|
|
||||||
// Info
|
// Info
|
||||||
flogger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String())
|
flogger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String())
|
||||||
flogger.Info("Use compression: %v", compression)
|
flogger.Info("Use compression: %v", compression)
|
||||||
flogger.Info("Round: %v", round)
|
flogger.Info("Round: %v", round)
|
||||||
|
|
||||||
ticker := time.Tick(cleanCacheInterval)
|
ticker := time.Tick(cleanCacheInterval)
|
||||||
|
|
||||||
interrupt := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
|
|
||||||
|
|
||||||
errorChannel := make(chan error, 0)
|
|
||||||
measuredValuesChannel := make(chan []*types.MeasuredValue, 0)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
childContext, cancel := context.WithCancel(ctx)
|
|
||||||
|
|
||||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
|
||||||
|
|
||||||
measuredValuesCache := make([]*types.MeasuredValue, 0)
|
measuredValuesCache := make([]*types.MeasuredValue, 0)
|
||||||
|
// measuredValuesLogfile := logfile.New(cnf.Logfile)
|
||||||
|
|
||||||
var postgres db.Database
|
// Producer
|
||||||
if cnf.DatabaseSettings != nil {
|
go sensor.ReadContinuously(ctx, cnf.GetSensors(config.ENABLED), measuredValueChannel, errorChannel)
|
||||||
p, err := db.New(cnf.DatabaseSettings)
|
|
||||||
if err != nil {
|
|
||||||
flogger.Error("%v", err)
|
|
||||||
}
|
|
||||||
if err := p.Schema(ctx, version); err != nil {
|
|
||||||
flogger.Error("%v", err)
|
|
||||||
}
|
|
||||||
postgres = p
|
|
||||||
checkDeviceInDatabase(ctx, cnf.Device, postgres)
|
|
||||||
checkSensorsInDatabase(ctx, cnf.Sensors, postgres)
|
|
||||||
defer postgres.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
// Distributor
|
||||||
|
//measuredValueChannels := distribute.MeasuredValues(ctx, 5, measuredValueChannel)
|
||||||
go sensor.ReadContinuously(childContext, cnf.GetSensors(config.ENABLED), measuredValuesChannel, errorChannel)
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
err := rgbled.Run(rgbLEDs)
|
|
||||||
if err != nil {
|
|
||||||
flogger.Error("Can not turn on green info light: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
case debug, _ := <-debugChannel:
|
||||||
|
flogger.Debug("%v", debug)
|
||||||
|
case info, _ := <-infoChannel:
|
||||||
|
flogger.Info("%v", info)
|
||||||
|
case warn, _ := <-warnChannel:
|
||||||
|
flogger.Warn("%v", warn)
|
||||||
case err, _ := <-errorChannel:
|
case err, _ := <-errorChannel:
|
||||||
|
|
||||||
flogger.Error("%v", err)
|
flogger.Error("%v", err)
|
||||||
|
case fatal, _ := <-fatalChannel:
|
||||||
err = rgbled.Error(rgbLEDs)
|
flogger.Fatal("Received a fatal error: %v", fatal)
|
||||||
if err != nil {
|
case interrupt := <-interruptChannel:
|
||||||
flogger.Error("Can not turn on red info light: %v", err)
|
flogger.Info("Received OS Signal: %v", interrupt)
|
||||||
}
|
flogger.Info("Close context")
|
||||||
|
cancel()
|
||||||
time.Sleep(time.Second * 2)
|
flogger.Info("Close channels")
|
||||||
|
close(debugChannel)
|
||||||
|
close(infoChannel)
|
||||||
|
close(warnChannel)
|
||||||
|
close(errorChannel)
|
||||||
|
close(interruptChannel)
|
||||||
|
return
|
||||||
|
|
||||||
case <-ticker:
|
case <-ticker:
|
||||||
err := rgbled.Logfile(rgbLEDs)
|
|
||||||
if err != nil {
|
|
||||||
flogger.Error("Can not turn on blue info light: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if round != 0 {
|
if round != 0 {
|
||||||
storage.Round(measuredValuesCache, round)
|
storage.Round(measuredValuesCache, round)
|
||||||
@ -111,46 +99,14 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress
|
|||||||
measuredValuesCache = storage.Compression(measuredValuesCache)
|
measuredValuesCache = storage.Compression(measuredValuesCache)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := logfile.Append(measuredValuesLogfile, measuredValuesCache); err != nil {
|
// if err := logfile.Append(measuredValuesLogfile, measuredValuesCache); err != nil {
|
||||||
err2 := rgbled.Error(rgbLEDs)
|
// flogger.Error("Can not save caches measured values in logfile: %v", err)
|
||||||
if err2 != nil {
|
// }
|
||||||
flogger.Error("Can not turn on red info light: %v", err2)
|
|
||||||
}
|
|
||||||
flogger.Error("Can not save caches measured values in logfile: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if postgres != nil {
|
|
||||||
if err := postgres.InsertMeasuredValues(ctx, measuredValuesCache); err != nil {
|
|
||||||
err2 := rgbled.Error(rgbLEDs)
|
|
||||||
if err2 != nil {
|
|
||||||
flogger.Error("Can not turn on red info light: %v", err)
|
|
||||||
}
|
|
||||||
flogger.Error("Can not save cached measured values in database: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
measuredValuesCache = make([]*types.MeasuredValue, 0)
|
measuredValuesCache = make([]*types.MeasuredValue, 0)
|
||||||
|
|
||||||
case measuredValues, _ := <-measuredValuesChannel:
|
case measuredValue, _ := <-measuredValueChannel:
|
||||||
measuredValuesCache = append(measuredValuesCache, measuredValues...)
|
measuredValuesCache = append(measuredValuesCache, measuredValue)
|
||||||
|
|
||||||
case killSignal := <-interrupt:
|
|
||||||
flogger.Warn("Daemon was interruped by system signal %v\n", killSignal)
|
|
||||||
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
err := rgbled.Error(rgbLEDs)
|
|
||||||
if err != nil {
|
|
||||||
flogger.Error("Can not turn on red info light: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flogger.Warn("Save remaining data from the cache")
|
|
||||||
err = logfile.Append(measuredValuesLogfile, measuredValuesCache)
|
|
||||||
if err != nil {
|
|
||||||
flogger.Fatal("%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import (
|
|||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MeasuredValues(measuredValuesChannel <-chan []*types.MeasuredValue) []*types.MeasuredValue {
|
func MeasuredValues(measuredValueChannel <-chan *types.MeasuredValue) []*types.MeasuredValue {
|
||||||
cachedMeasuredValues := make([]*types.MeasuredValue, 0)
|
cachedMeasuredValues := make([]*types.MeasuredValue, 0)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case measuredValues, more := <-measuredValuesChannel:
|
case measuredValue, more := <-measuredValueChannel:
|
||||||
if more {
|
if more {
|
||||||
cachedMeasuredValues = append(cachedMeasuredValues, measuredValues...)
|
cachedMeasuredValues = append(cachedMeasuredValues, measuredValue)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
30
pkg/internal/distribute/distribute.go
Normal file
30
pkg/internal/distribute/distribute.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package distribute
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MeasuredValues(ctx context.Context, channels int, inputChannel <-chan *types.MeasuredValue) []chan *types.MeasuredValue {
|
||||||
|
outputChannels := make([]chan *types.MeasuredValue, channels)
|
||||||
|
|
||||||
|
for i := 0; i <= channels; i++ {
|
||||||
|
outputChannel := make(chan *types.MeasuredValue)
|
||||||
|
outputChannels = append(outputChannels, outputChannel)
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(ctx context.Context, inputChannel <-chan *types.MeasuredValue, outputChannels []chan *types.MeasuredValue) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case measuredValue, _ := <-inputChannel:
|
||||||
|
for _, outputChannel := range outputChannels {
|
||||||
|
outputChannel <- measuredValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(ctx, inputChannel, outputChannels)
|
||||||
|
|
||||||
|
return outputChannels
|
||||||
|
}
|
@ -94,7 +94,7 @@ func (s *BME280) Read() ([]*types.MeasuredValue, error) {
|
|||||||
|
|
||||||
// ReadChannel reads the measured values from the sensor and writes them to a
|
// ReadChannel reads the measured values from the sensor and writes them to a
|
||||||
// channel.
|
// channel.
|
||||||
func (s *BME280) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
func (s *BME280) ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
||||||
if wg != nil {
|
if wg != nil {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
}
|
}
|
||||||
@ -105,20 +105,22 @@ func (s *BME280) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredValuesChannel <- measuredValues
|
for _, measuredValue := range measuredValues {
|
||||||
|
measuredValueChannel <- measuredValue
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadContinously reads the measured values continously from the sensor and
|
// ReadContinously reads the measured values continously from the sensor and
|
||||||
// writes them to a channel.
|
// writes them to a channel.
|
||||||
func (s *BME280) ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func (s *BME280) ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
s.ReadChannel(measuredValuesChannel, errorChannel, nil)
|
s.ReadChannel(measuredValueChannel, errorChannel, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (s *DHT11) Read() ([]*types.MeasuredValue, error) {
|
|||||||
|
|
||||||
// ReadChannel reads the measured values from the sensor and writes them to a
|
// ReadChannel reads the measured values from the sensor and writes them to a
|
||||||
// channel.
|
// channel.
|
||||||
func (s *DHT11) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
func (s *DHT11) ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
||||||
if wg != nil {
|
if wg != nil {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
}
|
}
|
||||||
@ -79,20 +79,22 @@ func (s *DHT11) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredValuesChannel <- measuredValues
|
for _, measuredValue := range measuredValues {
|
||||||
|
measuredValueChannel <- measuredValue
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadContinously reads the measured values continously from the sensor and
|
// ReadContinously reads the measured values continously from the sensor and
|
||||||
// writes them to a channel.
|
// writes them to a channel.
|
||||||
func (s *DHT11) ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func (s *DHT11) ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
s.ReadChannel(measuredValuesChannel, errorChannel, nil)
|
s.ReadChannel(measuredValueChannel, errorChannel, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ func (s *DHT22) Read() ([]*types.MeasuredValue, error) {
|
|||||||
|
|
||||||
// ReadChannel reads the measured values from the sensor and writes them to a
|
// ReadChannel reads the measured values from the sensor and writes them to a
|
||||||
// channel.
|
// channel.
|
||||||
func (s *DHT22) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
func (s *DHT22) ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
||||||
if wg != nil {
|
if wg != nil {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
}
|
}
|
||||||
@ -79,20 +79,22 @@ func (s *DHT22) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredValuesChannel <- measuredValues
|
for _, measuredValue := range measuredValues {
|
||||||
|
measuredValueChannel <- measuredValue
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadContinously reads the measured values continously from the sensor and
|
// ReadContinously reads the measured values continously from the sensor and
|
||||||
// writes them to a channel.
|
// writes them to a channel.
|
||||||
func (s *DHT22) ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func (s *DHT22) ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
s.ReadChannel(measuredValuesChannel, errorChannel, nil)
|
s.ReadChannel(measuredValueChannel, errorChannel, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ func (s *DS18B20) Read() ([]*types.MeasuredValue, error) {
|
|||||||
|
|
||||||
// ReadChannel reads the measured values from the sensor and writes them to a
|
// ReadChannel reads the measured values from the sensor and writes them to a
|
||||||
// channel.
|
// channel.
|
||||||
func (s *DS18B20) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
func (s *DS18B20) ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup) {
|
||||||
if wg != nil {
|
if wg != nil {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
}
|
}
|
||||||
@ -78,20 +78,22 @@ func (s *DS18B20) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValu
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredValuesChannel <- measuredValues
|
for _, measuredValue := range measuredValues {
|
||||||
|
measuredValueChannel <- measuredValue
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadContinously reads the measured values continously from the sensor and
|
// ReadContinously reads the measured values continously from the sensor and
|
||||||
// writes them to a channel.
|
// writes them to a channel.
|
||||||
func (s *DS18B20) ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func (s *DS18B20) ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
s.ReadChannel(measuredValuesChannel, errorChannel, nil)
|
s.ReadChannel(measuredValueChannel, errorChannel, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,6 @@ import (
|
|||||||
type Sensor interface {
|
type Sensor interface {
|
||||||
GetSensorModel() types.SensorModel
|
GetSensorModel() types.SensorModel
|
||||||
Read() ([]*types.MeasuredValue, error)
|
Read() ([]*types.MeasuredValue, error)
|
||||||
ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup)
|
ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup)
|
||||||
ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error)
|
ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error)
|
||||||
}
|
}
|
||||||
|
@ -14,30 +14,30 @@ import (
|
|||||||
// Read measured values from sensors
|
// Read measured values from sensors
|
||||||
func Read(ctx context.Context, sensors []Sensor) ([]*types.MeasuredValue, error) {
|
func Read(ctx context.Context, sensors []Sensor) ([]*types.MeasuredValue, error) {
|
||||||
|
|
||||||
measuredValuesChannel := make(chan []*types.MeasuredValue, len(sensors))
|
measuredValueChannel := make(chan *types.MeasuredValue, len(sensors))
|
||||||
errorChannel := make(chan error, len(sensors))
|
errorChannel := make(chan error, len(sensors))
|
||||||
|
|
||||||
ReadChannel(ctx, sensors, measuredValuesChannel, errorChannel)
|
ReadChannel(ctx, sensors, measuredValueChannel, errorChannel)
|
||||||
|
|
||||||
errors := collect.Errors(errorChannel)
|
errors := collect.Errors(errorChannel)
|
||||||
if len(errors) > 0 {
|
if len(errors) > 0 {
|
||||||
return nil, prittyprint.FormatErrors(errors)
|
return nil, prittyprint.FormatErrors(errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredValues := collect.MeasuredValues(measuredValuesChannel)
|
measuredValues := collect.MeasuredValues(measuredValueChannel)
|
||||||
|
|
||||||
return measuredValues, nil
|
return measuredValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadChannel reads the measured values from sensors and writes them to a
|
// ReadChannel reads the measured values from sensors and writes them to a
|
||||||
// channel.
|
// channel.
|
||||||
func ReadChannel(ctx context.Context, sensors []Sensor, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func ReadChannel(ctx context.Context, sensors []Sensor, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
|
|
||||||
wg := new(sync.WaitGroup)
|
wg := new(sync.WaitGroup)
|
||||||
wg.Add(len(sensors))
|
wg.Add(len(sensors))
|
||||||
|
|
||||||
for _, sensor := range sensors {
|
for _, sensor := range sensors {
|
||||||
go sensor.ReadChannel(measuredValuesChannel, errorChannel, wg)
|
go sensor.ReadChannel(measuredValueChannel, errorChannel, wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
@ -45,14 +45,14 @@ func ReadChannel(ctx context.Context, sensors []Sensor, measuredValuesChannel ch
|
|||||||
|
|
||||||
// ReadContinuously reads the measured values continously from sensors and writes
|
// ReadContinuously reads the measured values continously from sensors and writes
|
||||||
// them to a channel.
|
// them to a channel.
|
||||||
func ReadContinuously(ctx context.Context, sensors []Sensor, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error) {
|
func ReadContinuously(ctx context.Context, sensors []Sensor, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
errorChannel <- fmt.Errorf("Context closed: %v", ctx.Err())
|
errorChannel <- fmt.Errorf("Context closed: %v", ctx.Err())
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
ReadChannel(ctx, sensors, measuredValuesChannel, errorChannel)
|
ReadChannel(ctx, sensors, measuredValueChannel, errorChannel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package db
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/volker-raschek/go-logger/pkg/logger"
|
"github.com/volker-raschek/go-logger/pkg/logger"
|
||||||
)
|
)
|
||||||
@ -13,15 +13,14 @@ var (
|
|||||||
flogger = logger.NewSilentLogger()
|
flogger = logger.NewSilentLogger()
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(databaseSettings *config.DatabaseSettings) (Database, error) {
|
func New(storageEndpoint *url.URL) (Database, error) {
|
||||||
connStr := fmt.Sprintf("%v://%v:%v@%v:%v/%v?sslmode=disable", databaseSettings.Vendor.String(), databaseSettings.User, databaseSettings.Password, databaseSettings.Host, databaseSettings.Port, databaseSettings.Database)
|
newDBO, err := sql.Open(storageEndpoint.Scheme, storageEndpoint.String())
|
||||||
newDBO, err := sql.Open(databaseSettings.Vendor.String(), connStr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch databaseSettings.Vendor {
|
switch storageEndpoint.Scheme {
|
||||||
case config.VendorPostgreSQL:
|
case "postgres":
|
||||||
return &Postgres{
|
return &Postgres{
|
||||||
dbo: newDBO,
|
dbo: newDBO,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -29,6 +29,7 @@ type Database interface {
|
|||||||
SelectDeviceByID(ctx context.Context, id string) (*types.Device, error)
|
SelectDeviceByID(ctx context.Context, id string) (*types.Device, error)
|
||||||
SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error)
|
SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error)
|
||||||
SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error)
|
SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error)
|
||||||
|
SelectMeasuredValues(ctx context.Context) ([]*types.MeasuredValue, error)
|
||||||
SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error)
|
SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error)
|
||||||
SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error)
|
SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error)
|
||||||
SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error)
|
SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error)
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
|
|
||||||
|
// PostgreSQL lib
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,17 +20,19 @@ var (
|
|||||||
postgresAssetPath = "pkg/storage/db/sql/psql"
|
postgresAssetPath = "pkg/storage/db/sql/psql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Postgres provide functions to interact with a postgres database
|
||||||
type Postgres struct {
|
type Postgres struct {
|
||||||
dbo *sql.DB
|
dbo *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the database connection
|
||||||
func (p *Postgres) Close() error {
|
func (p *Postgres) Close() error {
|
||||||
return p.dbo.Close()
|
return p.dbo.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema create or upgrade database schema to the version of the flucky binary
|
// Schema create or updates the database schema to a given version. Normally the
|
||||||
|
// version is the same as the flucky binary version.
|
||||||
func (p *Postgres) Schema(ctx context.Context, version *semver.Version) error {
|
func (p *Postgres) Schema(ctx context.Context, version *semver.Version) error {
|
||||||
|
|
||||||
schemaFunc := func(ctx context.Context, fromVersion *semver.Version, toVersion *semver.Version) error {
|
schemaFunc := func(ctx context.Context, fromVersion *semver.Version, toVersion *semver.Version) error {
|
||||||
|
|
||||||
assetPath := fmt.Sprintf("%v/schema", postgresAssetPath)
|
assetPath := fmt.Sprintf("%v/schema", postgresAssetPath)
|
||||||
@ -94,9 +98,10 @@ func (p *Postgres) Schema(ctx context.Context, version *semver.Version) error {
|
|||||||
}
|
}
|
||||||
return schemaFunc(ctx, fromVersion, version)
|
return schemaFunc(ctx, fromVersion, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteDevices delete recursively all spicified devices, including sensors and
|
||||||
|
// all measured values
|
||||||
func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) error {
|
func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) error {
|
||||||
asset := fmt.Sprintf("%v/deleteDevice.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/deleteDevice.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -121,6 +126,8 @@ func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteSensors delete recusively all spicified sensors, including all measured
|
||||||
|
// values
|
||||||
func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) error {
|
func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) error {
|
||||||
asset := fmt.Sprintf("%v/deleteSensor.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/deleteSensor.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -145,6 +152,7 @@ func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteMeasuredValues delete all spicified measured values
|
||||||
func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
||||||
|
|
||||||
deleteMeasuredValue := func(ctx context.Context, query string, measuredValues []*types.MeasuredValue) error {
|
deleteMeasuredValue := func(ctx context.Context, query string, measuredValues []*types.MeasuredValue) error {
|
||||||
@ -214,6 +222,7 @@ func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*t
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertDevices insert all specified devices into the database
|
||||||
func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) error {
|
func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) error {
|
||||||
asset := fmt.Sprintf("%v/insertDevice.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/insertDevice.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -238,6 +247,7 @@ func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertInfo insert into the database additional informations, based on a key value syntax
|
||||||
func (p *Postgres) InsertInfo(ctx context.Context, key string, value string) error {
|
func (p *Postgres) InsertInfo(ctx context.Context, key string, value string) error {
|
||||||
asset := fmt.Sprintf("%v/insertInfo.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/insertInfo.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -260,6 +270,7 @@ func (p *Postgres) InsertInfo(ctx context.Context, key string, value string) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertMeasuredValues insert all specified measured values into the database
|
||||||
func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
||||||
|
|
||||||
sortedMeasuredValueTypes := make(map[types.MeasuredValueType][]*types.MeasuredValue)
|
sortedMeasuredValueTypes := make(map[types.MeasuredValueType][]*types.MeasuredValue)
|
||||||
@ -343,7 +354,7 @@ func (p *Postgres) insertPressure(ctx context.Context, measuredValues []*types.M
|
|||||||
|
|
||||||
_, err := stmt.ExecContext(ctx, &measuredValue.ID, &measuredValue.Value, &measuredValue.FromDate, &measuredValue.TillDate, &measuredValue.SensorID, &measuredValue.CreationDate, &measuredValue.UpdateDate)
|
_, err := stmt.ExecContext(ctx, &measuredValue.ID, &measuredValue.Value, &measuredValue.FromDate, &measuredValue.TillDate, &measuredValue.SensorID, &measuredValue.CreationDate, &measuredValue.UpdateDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%v: %v", errorStatementExecute, err)
|
return fmt.Errorf("%v: Measured value id %v: %v", errorStatementExecute, measuredValue.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -372,12 +383,13 @@ func (p *Postgres) insertTemperature(ctx context.Context, measuredValues []*type
|
|||||||
|
|
||||||
_, err := stmt.ExecContext(ctx, &measuredValue.ID, &measuredValue.Value, &measuredValue.FromDate, &measuredValue.TillDate, &measuredValue.SensorID, &measuredValue.CreationDate, &measuredValue.UpdateDate)
|
_, err := stmt.ExecContext(ctx, &measuredValue.ID, &measuredValue.Value, &measuredValue.FromDate, &measuredValue.TillDate, &measuredValue.SensorID, &measuredValue.CreationDate, &measuredValue.UpdateDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%v: %v", errorStatementExecute, err)
|
return fmt.Errorf("%v: Measured value id %v: %v", errorStatementExecute, measuredValue.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertSensors insert all specified sensors into the database
|
||||||
func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) error {
|
func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) error {
|
||||||
|
|
||||||
asset := fmt.Sprintf("%v/insertSensor.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/insertSensor.sql", postgresAssetPath)
|
||||||
@ -403,6 +415,7 @@ func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectDeviceByID returns a device by his ID
|
||||||
func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) {
|
func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) {
|
||||||
asset := fmt.Sprintf("%v/selectDeviceByID.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/selectDeviceByID.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -430,6 +443,7 @@ func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Devi
|
|||||||
return device, nil
|
return device, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectInfo returns the value of a key stored in the database
|
||||||
func (p *Postgres) SelectInfo(ctx context.Context, key string) (string, error) {
|
func (p *Postgres) SelectInfo(ctx context.Context, key string) (string, error) {
|
||||||
asset := fmt.Sprintf("%v/selectInfo.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/selectInfo.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -457,6 +471,7 @@ func (p *Postgres) SelectInfo(ctx context.Context, key string) (string, error) {
|
|||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectHumidities returns humidity values
|
||||||
func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
|
func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectHumidities.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectHumidities.sql", postgresAssetPath)
|
||||||
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, nil)
|
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, nil)
|
||||||
@ -466,6 +481,7 @@ func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue
|
|||||||
return measuredValues, nil
|
return measuredValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectHumidityByID returns a humidity value by his ID
|
||||||
func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectHumidityByID.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectHumidityByID.sql", postgresAssetPath)
|
||||||
args := []interface{}{id}
|
args := []interface{}{id}
|
||||||
@ -481,6 +497,30 @@ func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.Me
|
|||||||
return measuredValues[0], nil
|
return measuredValues[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectMeasuredValues returns all measured values about all diffferent value
|
||||||
|
// types
|
||||||
|
func (p *Postgres) SelectMeasuredValues(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||||
|
measuredValues := make([]*types.MeasuredValue, 0)
|
||||||
|
|
||||||
|
// MeasuredValue query functions
|
||||||
|
queryFunctions := []func(ctx context.Context) ([]*types.MeasuredValue, error){
|
||||||
|
p.SelectHumidities,
|
||||||
|
p.SelectPressures,
|
||||||
|
p.SelectTemperatures,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute query functions
|
||||||
|
for _, queryFunction := range queryFunctions {
|
||||||
|
queriedMeasuredValues, err := queryFunction(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
measuredValues = append(measuredValues, queriedMeasuredValues...)
|
||||||
|
}
|
||||||
|
return measuredValues, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMeasuredValuesByIDAndType returns a measured value by his ID and type
|
||||||
func (p *Postgres) SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error) {
|
func (p *Postgres) SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error) {
|
||||||
switch valueType {
|
switch valueType {
|
||||||
case types.MeasuredValueTypeHumidity:
|
case types.MeasuredValueTypeHumidity:
|
||||||
@ -494,6 +534,7 @@ func (p *Postgres) SelectMeasuredValuesByIDAndType(ctx context.Context, id strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectPressures returns pressure values
|
||||||
func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectPressures.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectPressures.sql", postgresAssetPath)
|
||||||
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, nil)
|
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, nil)
|
||||||
@ -503,6 +544,7 @@ func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue,
|
|||||||
return measuredValues, nil
|
return measuredValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectPressureByID returns a pressure value by his ID
|
||||||
func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectPressureByID.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectPressureByID.sql", postgresAssetPath)
|
||||||
args := []interface{}{id}
|
args := []interface{}{id}
|
||||||
@ -518,6 +560,7 @@ func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.Me
|
|||||||
return measuredValues[0], nil
|
return measuredValues[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectSensorByID returns a sensor by his ID
|
||||||
func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sensor, error) {
|
func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sensor, error) {
|
||||||
asset := fmt.Sprintf("%v/selectSensorByID.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/selectSensorByID.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -545,6 +588,7 @@ func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sens
|
|||||||
return sensor, nil
|
return sensor, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectTemperatures returns temperature values
|
||||||
func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectTemperatures.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectTemperatures.sql", postgresAssetPath)
|
||||||
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, nil)
|
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, nil)
|
||||||
@ -554,6 +598,7 @@ func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredVal
|
|||||||
return measuredValues, nil
|
return measuredValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectTemperatureByID returns a temperature value by his ID
|
||||||
func (p *Postgres) SelectTemperatureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
func (p *Postgres) SelectTemperatureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||||
queryFile := fmt.Sprintf("%v/selectTemperatureByID.sql", postgresAssetPath)
|
queryFile := fmt.Sprintf("%v/selectTemperatureByID.sql", postgresAssetPath)
|
||||||
args := []interface{}{id}
|
args := []interface{}{id}
|
||||||
@ -597,10 +642,12 @@ func (p *Postgres) selectMeasuredValues(ctx context.Context, measuredValueType t
|
|||||||
return measuredValues, nil
|
return measuredValues, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateDevices updates all specified devices into the database
|
||||||
func (p *Postgres) UpdateDevices(ctx context.Context, devices []*types.Device) error {
|
func (p *Postgres) UpdateDevices(ctx context.Context, devices []*types.Device) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateInfo updates the value which is stored to a key in the database
|
||||||
func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) error {
|
func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) error {
|
||||||
asset := fmt.Sprintf("%v/updateInfo.sql", postgresAssetPath)
|
asset := fmt.Sprintf("%v/updateInfo.sql", postgresAssetPath)
|
||||||
queryBytes, err := Asset(asset)
|
queryBytes, err := Asset(asset)
|
||||||
@ -623,10 +670,12 @@ func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateMeasuredValues updates the measured values which are stored in the database
|
||||||
func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateSensors updates the sensors which are stored in the database
|
||||||
func (p *Postgres) UpdateSensors(ctx context.Context, sensots []*types.Sensor) error {
|
func (p *Postgres) UpdateSensors(ctx context.Context, sensots []*types.Sensor) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ package db_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/Masterminds/semver"
|
"github.com/Masterminds/semver"
|
||||||
"github.com/go-flucky/flucky/pkg/config"
|
|
||||||
"github.com/go-flucky/flucky/pkg/storage/db"
|
"github.com/go-flucky/flucky/pkg/storage/db"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
"github.com/go-flucky/flucky/test/goldenfiles"
|
"github.com/go-flucky/flucky/test/goldenfiles"
|
||||||
@ -23,14 +23,7 @@ var (
|
|||||||
|
|
||||||
postgresContainerImage string = "docker.io/postgres/postgres"
|
postgresContainerImage string = "docker.io/postgres/postgres"
|
||||||
|
|
||||||
postgresSettings = &config.DatabaseSettings{
|
storageEndpointString string = "postgres://flucky:flucky@markus-pc.trier.cryptic.systems/postgres?sslmode=disable"
|
||||||
Vendor: config.VendorPostgreSQL,
|
|
||||||
Host: "localhost",
|
|
||||||
Port: "5432",
|
|
||||||
User: "postgres",
|
|
||||||
Password: "postgres",
|
|
||||||
Database: "postgres",
|
|
||||||
}
|
|
||||||
|
|
||||||
goldenDevicesFilePath string = "test/goldenfiles/json/goldenDevices.json"
|
goldenDevicesFilePath string = "test/goldenfiles/json/goldenDevices.json"
|
||||||
goldenSensorsFilePath string = "test/goldenfiles/json/goldenSensors.json"
|
goldenSensorsFilePath string = "test/goldenfiles/json/goldenSensors.json"
|
||||||
@ -81,7 +74,10 @@ func TestPostgres(t *testing.T) {
|
|||||||
|
|
||||||
load(t)
|
load(t)
|
||||||
|
|
||||||
db, err := db.New(postgresSettings)
|
storageEndpoint, err := url.Parse(storageEndpointString)
|
||||||
|
require.Nil(err)
|
||||||
|
|
||||||
|
db, err := db.New(storageEndpoint)
|
||||||
database = db
|
database = db
|
||||||
require.Nil(err)
|
require.Nil(err)
|
||||||
|
|
||||||
|
3
pkg/storage/db/sql/psql/schema/v0.1.1.sql
Normal file
3
pkg/storage/db/sql/psql/schema/v0.1.1.sql
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE humidities ALTER COLUMN creation_date DROP NOT NULL;
|
||||||
|
ALTER TABLE pressures ALTER COLUMN creation_date DROP NOT NULL;
|
||||||
|
ALTER TABLE temperatures ALTER COLUMN creation_date DROP NOT NULL;
|
@ -1,10 +1,15 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
"net/url"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/go-flucky/flucky/pkg/internal/format"
|
"github.com/go-flucky/flucky/pkg/internal/format"
|
||||||
|
"github.com/go-flucky/flucky/pkg/storage/db"
|
||||||
|
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
||||||
"github.com/go-flucky/flucky/pkg/types"
|
"github.com/go-flucky/flucky/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,8 +68,49 @@ func Compression(measuredValues []*types.MeasuredValue) []*types.MeasuredValue {
|
|||||||
return compressedMeasuredValues
|
return compressedMeasuredValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read measured values from the given storage endpoint url. The scheme must be
|
||||||
|
// matched to a provider, if the scheme is not implemented, the function
|
||||||
|
// returns an error
|
||||||
|
func Read(ctx context.Context, storageEndpoint *url.URL) ([]*types.MeasuredValue, error) {
|
||||||
|
switch storageEndpoint.Scheme {
|
||||||
|
case "file":
|
||||||
|
measuredValueLogfile := logfile.New(storageEndpoint.Path)
|
||||||
|
return measuredValueLogfile.Read()
|
||||||
|
case "postgres":
|
||||||
|
database, err := db.New(storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
return database.SelectMeasuredValues(ctx)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("No supported scheme")
|
||||||
|
}
|
||||||
|
|
||||||
func Round(measuredValues []*types.MeasuredValue, round float64) {
|
func Round(measuredValues []*types.MeasuredValue, round float64) {
|
||||||
for _, measuredValue := range measuredValues {
|
for _, measuredValue := range measuredValues {
|
||||||
measuredValue.Value = math.Round(measuredValue.Value/round) * round
|
measuredValue.Value = math.Round(measuredValue.Value/round) * round
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write measured values to the given storage endpoint url. The scheme must be
|
||||||
|
// matched to a provider, if the scheme is not implemented, the function
|
||||||
|
// returns an error
|
||||||
|
func Write(ctx context.Context, measuredValues []*types.MeasuredValue, storageEndpoint *url.URL) error {
|
||||||
|
switch storageEndpoint.Scheme {
|
||||||
|
case "file":
|
||||||
|
measuredValueLogfile := logfile.New(storageEndpoint.Path)
|
||||||
|
return measuredValueLogfile.Write(measuredValues)
|
||||||
|
case "postgres":
|
||||||
|
database, err := db.New(storageEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
|
||||||
|
if err := database.InsertMeasuredValues(ctx, measuredValues); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("No supported scheme")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user