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,
|
||||
CreationDate: t,
|
||||
},
|
||||
Logfile: "/var/log/flucky/logfile.csv",
|
||||
StorageEndpoint: "file:///var/log/flucky/logfile.csv",
|
||||
}
|
||||
|
||||
err = config.Write(&cnf, configFile)
|
||||
|
@ -50,5 +50,5 @@ func InitCmd(cmd *cobra.Command, cnfFile *string, sversion *semver.Version) {
|
||||
cmd.AddCommand(daemonCmd)
|
||||
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().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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -22,33 +16,33 @@ var dbCmd = &cobra.Command{
|
||||
Short: "Operates with the configured database",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// read configuration
|
||||
cnf, err := config.Read(*configFile)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// // read configuration
|
||||
// cnf, err := config.Read(*configFile)
|
||||
// if err != nil {
|
||||
// log.Fatalln(err)
|
||||
// }
|
||||
|
||||
postgresDB, err := database.New(cnf.DatabaseSettings)
|
||||
if err != nil {
|
||||
log.Fatalf("%v", err)
|
||||
}
|
||||
// postgresDB, err := database.New(cnf.DatabaseSettings)
|
||||
// if err != nil {
|
||||
// log.Fatalf("%v", err)
|
||||
// }
|
||||
|
||||
ctx := context.Background()
|
||||
// ctx := context.Background()
|
||||
|
||||
devices := []*types.Device{
|
||||
&types.Device{
|
||||
DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||
DeviceName: "raspberr-pi",
|
||||
},
|
||||
&types.Device{
|
||||
DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||
DeviceName: "raspberr-pi",
|
||||
},
|
||||
}
|
||||
// devices := []*types.Device{
|
||||
// &types.Device{
|
||||
// DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||
// DeviceName: "raspberr-pi",
|
||||
// },
|
||||
// &types.Device{
|
||||
// DeviceID: "1684df26-bc72-4435-a4f9-74b24bdb286c",
|
||||
// DeviceName: "raspberr-pi",
|
||||
// },
|
||||
// }
|
||||
|
||||
if err := postgresDB.InsertDevices(ctx, devices); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
// if err := postgresDB.InsertDevices(ctx, devices); err != nil {
|
||||
// log.Fatalln(err)
|
||||
// }
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
package humidity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"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/cli"
|
||||
"github.com/go-flucky/flucky/pkg/config"
|
||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -26,19 +26,14 @@ var listTemperatureCmd = &cobra.Command{
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
logfile := logfile.New(cnf.Logfile)
|
||||
|
||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
measuredValues, err := logfile.Read()
|
||||
ctx := context.Background()
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
||||
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"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/cli"
|
||||
@ -56,8 +56,12 @@ var readHumidityCmd = &cobra.Command{
|
||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||
|
||||
if logs {
|
||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package pressure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-flucky/flucky/pkg/cli"
|
||||
"github.com/go-flucky/flucky/pkg/config"
|
||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
||||
"github.com/go-flucky/flucky/pkg/storage/logfile"
|
||||
"github.com/go-flucky/flucky/pkg/storage"
|
||||
"github.com/go-flucky/flucky/pkg/types"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -25,19 +25,14 @@ var listTemperatureCmd = &cobra.Command{
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
logfile := logfile.New(cnf.Logfile)
|
||||
|
||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
measuredValues, err := logfile.Read()
|
||||
ctx := context.Background()
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
||||
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"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/cli"
|
||||
@ -56,8 +56,12 @@ var readPressureCmd = &cobra.Command{
|
||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||
|
||||
if logs {
|
||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package temperature
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"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/cli"
|
||||
"github.com/go-flucky/flucky/pkg/config"
|
||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@ -26,19 +26,14 @@ var listTemperatureCmd = &cobra.Command{
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
logfile := logfile.New(cnf.Logfile)
|
||||
|
||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
||||
if err := rgbled.Logfile(rgbLEDs); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
measuredValues, err := logfile.Read()
|
||||
ctx := context.Background()
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if err := rgbled.Off(rgbLEDs); err != nil {
|
||||
measuredValues, err := storage.Read(ctx, storageEndpoint)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/go-flucky/flucky/pkg/rgbled"
|
||||
"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/cli"
|
||||
@ -42,15 +41,9 @@ var readTemperatureCmd = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
||||
if err := rgbled.Run(rgbLEDs); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
measuredValues, err := sensor.Read(ctx, sensors)
|
||||
if err != nil {
|
||||
rgbled.Error(rgbLEDs)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
@ -60,14 +53,16 @@ var readTemperatureCmd = &cobra.Command{
|
||||
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
|
||||
|
||||
if logs {
|
||||
measuredValuesLogfile := logfile.New(cnf.Logfile)
|
||||
err := logfile.Append(measuredValuesLogfile, measuredValues)
|
||||
storageEndpoint, err := cnf.GetStorageEndpointURL()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
err = storage.Write(ctx, measuredValues, storageEndpoint)
|
||||
if err != nil {
|
||||
rgbled.Error(rgbLEDs)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
rgbled.Off(rgbLEDs)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -4,13 +4,13 @@ services:
|
||||
container_name: postgres
|
||||
environment:
|
||||
- PGTZ=${TZ}
|
||||
- POSTGRES_PASSWORD=${PG_PASSWORD}
|
||||
- POSTGRES_USER=${PG_USER}
|
||||
- POSTGRES_DB=${PG_NAME}
|
||||
- POSTGRES_DB=${POSTGRES_DB_NAME}
|
||||
- POSTGRES_USER=${POSTGRES_DB_USER}
|
||||
- POSTGRES_PASSWORD=${POSTGRES_DB_PASS}
|
||||
- TZ=${TZ}
|
||||
image: postgres:11.5-alpine
|
||||
ports:
|
||||
- ${PG_EXTERN_PORT}:${PG_INTERN_PORT}/tcp
|
||||
- 5432:5432
|
||||
restart: always
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
@ -1,59 +1,600 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"net/url"
|
||||
|
||||
"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}$")
|
||||
|
||||
// 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
|
||||
|
||||
// Configuration of flucky
|
||||
type Configuration struct {
|
||||
Device *types.Device `json:"device"`
|
||||
StorageEndpoint string `json:"storage_endpoint"`
|
||||
RGBLEDs []*types.RGBLED `json:"rgb_leds"`
|
||||
Sensors []*types.Sensor `json:"sensors"`
|
||||
}
|
||||
|
||||
// Write the configuration into a file, specified by the configuration filepath
|
||||
func Write(cfg *Configuration, configFile string) error {
|
||||
// AddRGBLED add a new RGBLED
|
||||
func (c *Configuration) AddRGBLED(rgbLED *types.RGBLED) 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)
|
||||
// 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 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)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can not write config file: %v", err)
|
||||
// check if sensor has a valid device id
|
||||
if sensor.DeviceID != c.Device.DeviceID {
|
||||
sensor.DeviceID = c.Device.DeviceID
|
||||
}
|
||||
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)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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/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/storage"
|
||||
"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/volker-raschek/go-logger/pkg/logger"
|
||||
)
|
||||
@ -25,12 +23,8 @@ var (
|
||||
postgresUser = "postgres"
|
||||
postgresPassword = "postgres"
|
||||
|
||||
flogger logger.Logger
|
||||
)
|
||||
|
||||
func init() {
|
||||
flogger = logger.NewSilentLogger()
|
||||
}
|
||||
)
|
||||
|
||||
func SetLogger(logger logger.Logger) {
|
||||
flogger = logger
|
||||
@ -39,69 +33,63 @@ func SetLogger(logger logger.Logger) {
|
||||
// Start the daemon
|
||||
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
|
||||
flogger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String())
|
||||
flogger.Info("Use compression: %v", compression)
|
||||
flogger.Info("Round: %v", round)
|
||||
|
||||
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)
|
||||
// measuredValuesLogfile := logfile.New(cnf.Logfile)
|
||||
|
||||
var postgres db.Database
|
||||
if cnf.DatabaseSettings != nil {
|
||||
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()
|
||||
}
|
||||
// Producer
|
||||
go sensor.ReadContinuously(ctx, cnf.GetSensors(config.ENABLED), measuredValueChannel, errorChannel)
|
||||
|
||||
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
|
||||
|
||||
go sensor.ReadContinuously(childContext, cnf.GetSensors(config.ENABLED), measuredValuesChannel, errorChannel)
|
||||
// Distributor
|
||||
//measuredValueChannels := distribute.MeasuredValues(ctx, 5, measuredValueChannel)
|
||||
|
||||
for {
|
||||
|
||||
err := rgbled.Run(rgbLEDs)
|
||||
if err != nil {
|
||||
flogger.Error("Can not turn on green info light: %v", err)
|
||||
}
|
||||
|
||||
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:
|
||||
|
||||
flogger.Error("%v", err)
|
||||
|
||||
err = rgbled.Error(rgbLEDs)
|
||||
if err != nil {
|
||||
flogger.Error("Can not turn on red info light: %v", err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
case fatal, _ := <-fatalChannel:
|
||||
flogger.Fatal("Received a fatal error: %v", fatal)
|
||||
case interrupt := <-interruptChannel:
|
||||
flogger.Info("Received OS Signal: %v", interrupt)
|
||||
flogger.Info("Close context")
|
||||
cancel()
|
||||
flogger.Info("Close channels")
|
||||
close(debugChannel)
|
||||
close(infoChannel)
|
||||
close(warnChannel)
|
||||
close(errorChannel)
|
||||
close(interruptChannel)
|
||||
return
|
||||
|
||||
case <-ticker:
|
||||
err := rgbled.Logfile(rgbLEDs)
|
||||
if err != nil {
|
||||
flogger.Error("Can not turn on blue info light: %v", err)
|
||||
}
|
||||
|
||||
if round != 0 {
|
||||
storage.Round(measuredValuesCache, round)
|
||||
@ -111,46 +99,14 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress
|
||||
measuredValuesCache = storage.Compression(measuredValuesCache)
|
||||
}
|
||||
|
||||
if err := logfile.Append(measuredValuesLogfile, measuredValuesCache); err != nil {
|
||||
err2 := rgbled.Error(rgbLEDs)
|
||||
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)
|
||||
}
|
||||
}
|
||||
// if err := logfile.Append(measuredValuesLogfile, measuredValuesCache); err != nil {
|
||||
// flogger.Error("Can not save caches measured values in logfile: %v", err)
|
||||
// }
|
||||
|
||||
measuredValuesCache = make([]*types.MeasuredValue, 0)
|
||||
|
||||
case measuredValues, _ := <-measuredValuesChannel:
|
||||
measuredValuesCache = append(measuredValuesCache, measuredValues...)
|
||||
|
||||
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
|
||||
case measuredValue, _ := <-measuredValueChannel:
|
||||
measuredValuesCache = append(measuredValuesCache, measuredValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ import (
|
||||
"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)
|
||||
for {
|
||||
select {
|
||||
case measuredValues, more := <-measuredValuesChannel:
|
||||
case measuredValue, more := <-measuredValueChannel:
|
||||
if more {
|
||||
cachedMeasuredValues = append(cachedMeasuredValues, measuredValues...)
|
||||
cachedMeasuredValues = append(cachedMeasuredValues, measuredValue)
|
||||
continue
|
||||
}
|
||||
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
|
||||
// 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 {
|
||||
defer wg.Done()
|
||||
}
|
||||
@ -105,20 +105,22 @@ func (s *BME280) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue
|
||||
return
|
||||
}
|
||||
|
||||
measuredValuesChannel <- measuredValues
|
||||
for _, measuredValue := range measuredValues {
|
||||
measuredValueChannel <- measuredValue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ReadContinously reads the measured values continously from the sensor and
|
||||
// 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 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||
return
|
||||
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
|
||||
// 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 {
|
||||
defer wg.Done()
|
||||
}
|
||||
@ -79,20 +79,22 @@ func (s *DHT11) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue,
|
||||
return
|
||||
}
|
||||
|
||||
measuredValuesChannel <- measuredValues
|
||||
for _, measuredValue := range measuredValues {
|
||||
measuredValueChannel <- measuredValue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ReadContinously reads the measured values continously from the sensor and
|
||||
// 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 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||
return
|
||||
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
|
||||
// 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 {
|
||||
defer wg.Done()
|
||||
}
|
||||
@ -79,20 +79,22 @@ func (s *DHT22) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue,
|
||||
return
|
||||
}
|
||||
|
||||
measuredValuesChannel <- measuredValues
|
||||
for _, measuredValue := range measuredValues {
|
||||
measuredValueChannel <- measuredValue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ReadContinously reads the measured values continously from the sensor and
|
||||
// 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 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||
return
|
||||
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
|
||||
// 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 {
|
||||
defer wg.Done()
|
||||
}
|
||||
@ -78,20 +78,22 @@ func (s *DS18B20) ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValu
|
||||
return
|
||||
}
|
||||
|
||||
measuredValuesChannel <- measuredValues
|
||||
for _, measuredValue := range measuredValues {
|
||||
measuredValueChannel <- measuredValue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ReadContinously reads the measured values continously from the sensor and
|
||||
// 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 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err())
|
||||
return
|
||||
default:
|
||||
s.ReadChannel(measuredValuesChannel, errorChannel, nil)
|
||||
s.ReadChannel(measuredValueChannel, errorChannel, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,6 @@ import (
|
||||
type Sensor interface {
|
||||
GetSensorModel() types.SensorModel
|
||||
Read() ([]*types.MeasuredValue, error)
|
||||
ReadChannel(measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup)
|
||||
ReadContinously(ctx context.Context, measuredValuesChannel chan<- []*types.MeasuredValue, errorChannel chan<- error)
|
||||
ReadChannel(measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error, wg *sync.WaitGroup)
|
||||
ReadContinously(ctx context.Context, measuredValueChannel chan<- *types.MeasuredValue, errorChannel chan<- error)
|
||||
}
|
||||
|
@ -14,30 +14,30 @@ import (
|
||||
// Read measured values from sensors
|
||||
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))
|
||||
|
||||
ReadChannel(ctx, sensors, measuredValuesChannel, errorChannel)
|
||||
ReadChannel(ctx, sensors, measuredValueChannel, errorChannel)
|
||||
|
||||
errors := collect.Errors(errorChannel)
|
||||
if len(errors) > 0 {
|
||||
return nil, prittyprint.FormatErrors(errors)
|
||||
}
|
||||
|
||||
measuredValues := collect.MeasuredValues(measuredValuesChannel)
|
||||
measuredValues := collect.MeasuredValues(measuredValueChannel)
|
||||
|
||||
return measuredValues, nil
|
||||
}
|
||||
|
||||
// ReadChannel reads the measured values from sensors and writes them to a
|
||||
// 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.Add(len(sensors))
|
||||
|
||||
for _, sensor := range sensors {
|
||||
go sensor.ReadChannel(measuredValuesChannel, errorChannel, wg)
|
||||
go sensor.ReadChannel(measuredValueChannel, errorChannel, wg)
|
||||
}
|
||||
|
||||
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
|
||||
// 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 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
errorChannel <- fmt.Errorf("Context closed: %v", ctx.Err())
|
||||
return
|
||||
default:
|
||||
ReadChannel(ctx, sensors, measuredValuesChannel, errorChannel)
|
||||
ReadChannel(ctx, sensors, measuredValueChannel, errorChannel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package db
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-flucky/flucky/pkg/config"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/volker-raschek/go-logger/pkg/logger"
|
||||
)
|
||||
@ -13,15 +13,14 @@ var (
|
||||
flogger = logger.NewSilentLogger()
|
||||
)
|
||||
|
||||
func New(databaseSettings *config.DatabaseSettings) (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(databaseSettings.Vendor.String(), connStr)
|
||||
func New(storageEndpoint *url.URL) (Database, error) {
|
||||
newDBO, err := sql.Open(storageEndpoint.Scheme, storageEndpoint.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch databaseSettings.Vendor {
|
||||
case config.VendorPostgreSQL:
|
||||
switch storageEndpoint.Scheme {
|
||||
case "postgres":
|
||||
return &Postgres{
|
||||
dbo: newDBO,
|
||||
}, nil
|
||||
|
@ -29,6 +29,7 @@ type Database interface {
|
||||
SelectDeviceByID(ctx context.Context, id string) (*types.Device, error)
|
||||
SelectHumidities(ctx context.Context) ([]*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)
|
||||
SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error)
|
||||
SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error)
|
||||
|
@ -11,6 +11,8 @@ import (
|
||||
"github.com/Masterminds/semver"
|
||||
|
||||
"github.com/go-flucky/flucky/pkg/types"
|
||||
|
||||
// PostgreSQL lib
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
@ -18,17 +20,19 @@ var (
|
||||
postgresAssetPath = "pkg/storage/db/sql/psql"
|
||||
)
|
||||
|
||||
// Postgres provide functions to interact with a postgres database
|
||||
type Postgres struct {
|
||||
dbo *sql.DB
|
||||
}
|
||||
|
||||
// Close the database connection
|
||||
func (p *Postgres) Close() error {
|
||||
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 {
|
||||
|
||||
schemaFunc := func(ctx context.Context, fromVersion *semver.Version, toVersion *semver.Version) error {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DeleteDevices delete recursively all spicified devices, including sensors and
|
||||
// all measured values
|
||||
func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) error {
|
||||
asset := fmt.Sprintf("%v/deleteDevice.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -121,6 +126,8 @@ func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteSensors delete recusively all spicified sensors, including all measured
|
||||
// values
|
||||
func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) error {
|
||||
asset := fmt.Sprintf("%v/deleteSensor.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -145,6 +152,7 @@ func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteMeasuredValues delete all spicified measured values
|
||||
func (p *Postgres) DeleteMeasuredValues(ctx context.Context, 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
|
||||
}
|
||||
|
||||
// InsertDevices insert all specified devices into the database
|
||||
func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) error {
|
||||
asset := fmt.Sprintf("%v/insertDevice.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -238,6 +247,7 @@ func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) e
|
||||
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 {
|
||||
asset := fmt.Sprintf("%v/insertInfo.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -260,6 +270,7 @@ func (p *Postgres) InsertInfo(ctx context.Context, key string, value string) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertMeasuredValues insert all specified measured values into the database
|
||||
func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
||||
|
||||
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)
|
||||
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
|
||||
@ -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)
|
||||
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
|
||||
}
|
||||
|
||||
// InsertSensors insert all specified sensors into the database
|
||||
func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) error {
|
||||
|
||||
asset := fmt.Sprintf("%v/insertSensor.sql", postgresAssetPath)
|
||||
@ -403,6 +415,7 @@ func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// SelectDeviceByID returns a device by his ID
|
||||
func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) {
|
||||
asset := fmt.Sprintf("%v/selectDeviceByID.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -430,6 +443,7 @@ func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Devi
|
||||
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) {
|
||||
asset := fmt.Sprintf("%v/selectInfo.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -457,6 +471,7 @@ func (p *Postgres) SelectInfo(ctx context.Context, key string) (string, error) {
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// SelectHumidities returns humidity values
|
||||
func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||
queryFile := fmt.Sprintf("%v/selectHumidities.sql", postgresAssetPath)
|
||||
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
|
||||
}
|
||||
|
||||
// SelectHumidityByID returns a humidity value by his ID
|
||||
func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||
queryFile := fmt.Sprintf("%v/selectHumidityByID.sql", postgresAssetPath)
|
||||
args := []interface{}{id}
|
||||
@ -481,6 +497,30 @@ func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.Me
|
||||
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) {
|
||||
switch valueType {
|
||||
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) {
|
||||
queryFile := fmt.Sprintf("%v/selectPressures.sql", postgresAssetPath)
|
||||
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
|
||||
}
|
||||
|
||||
// SelectPressureByID returns a pressure value by his ID
|
||||
func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||
queryFile := fmt.Sprintf("%v/selectPressureByID.sql", postgresAssetPath)
|
||||
args := []interface{}{id}
|
||||
@ -518,6 +560,7 @@ func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.Me
|
||||
return measuredValues[0], nil
|
||||
}
|
||||
|
||||
// SelectSensorByID returns a sensor by his ID
|
||||
func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sensor, error) {
|
||||
asset := fmt.Sprintf("%v/selectSensorByID.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -545,6 +588,7 @@ func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sens
|
||||
return sensor, nil
|
||||
}
|
||||
|
||||
// SelectTemperatures returns temperature values
|
||||
func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
|
||||
queryFile := fmt.Sprintf("%v/selectTemperatures.sql", postgresAssetPath)
|
||||
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
|
||||
}
|
||||
|
||||
// SelectTemperatureByID returns a temperature value by his ID
|
||||
func (p *Postgres) SelectTemperatureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
|
||||
queryFile := fmt.Sprintf("%v/selectTemperatureByID.sql", postgresAssetPath)
|
||||
args := []interface{}{id}
|
||||
@ -597,10 +642,12 @@ func (p *Postgres) selectMeasuredValues(ctx context.Context, measuredValueType t
|
||||
return measuredValues, nil
|
||||
}
|
||||
|
||||
// UpdateDevices updates all specified devices into the database
|
||||
func (p *Postgres) UpdateDevices(ctx context.Context, devices []*types.Device) error {
|
||||
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 {
|
||||
asset := fmt.Sprintf("%v/updateInfo.sql", postgresAssetPath)
|
||||
queryBytes, err := Asset(asset)
|
||||
@ -623,10 +670,12 @@ func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMeasuredValues updates the measured values which are stored in the database
|
||||
func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSensors updates the sensors which are stored in the database
|
||||
func (p *Postgres) UpdateSensors(ctx context.Context, sensots []*types.Sensor) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package db_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"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/types"
|
||||
"github.com/go-flucky/flucky/test/goldenfiles"
|
||||
@ -23,14 +23,7 @@ var (
|
||||
|
||||
postgresContainerImage string = "docker.io/postgres/postgres"
|
||||
|
||||
postgresSettings = &config.DatabaseSettings{
|
||||
Vendor: config.VendorPostgreSQL,
|
||||
Host: "localhost",
|
||||
Port: "5432",
|
||||
User: "postgres",
|
||||
Password: "postgres",
|
||||
Database: "postgres",
|
||||
}
|
||||
storageEndpointString string = "postgres://flucky:flucky@markus-pc.trier.cryptic.systems/postgres?sslmode=disable"
|
||||
|
||||
goldenDevicesFilePath string = "test/goldenfiles/json/goldenDevices.json"
|
||||
goldenSensorsFilePath string = "test/goldenfiles/json/goldenSensors.json"
|
||||
@ -81,7 +74,10 @@ func TestPostgres(t *testing.T) {
|
||||
|
||||
load(t)
|
||||
|
||||
db, err := db.New(postgresSettings)
|
||||
storageEndpoint, err := url.Parse(storageEndpointString)
|
||||
require.Nil(err)
|
||||
|
||||
db, err := db.New(storageEndpoint)
|
||||
database = db
|
||||
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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -63,8 +68,49 @@ func Compression(measuredValues []*types.MeasuredValue) []*types.MeasuredValue {
|
||||
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) {
|
||||
for _, measuredValue := range measuredValues {
|
||||
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