diff --git a/README.md b/README.md index 1feb0c8..88a74dc 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ You will be asked some questions during the initial configuration of TempGopher. * `Heating GPIO:` - The pin your heating relay switch is hooked into. * `Invert heating switch` - If set to `true`, the heating will be ON when the switch is LOW. This should usually be `false`, so that is the default * `Enable verbose logging` - If set to `true`, TempGopher will display in the console every thermostat reading. This can be quite verbose, so the default is `false`. +* `Write data to an Influx database?` - Whether or not to configure an Influx database ## Example configuration script @@ -73,4 +74,13 @@ Heating minutes: 0.5 Heating GPIO: 13 Invert heating switch [false]: Enable verbose logging [false]: +Write data to an Influx database? +[Y/n]: y +Influx address [http://influx:8086]: +Influx Username []: +Influx Password []: +Influx UserAgent [InfluxDBClient]: +Influx timeout (in seconds) [30]: +Influx database []: tempgopher +Enable InsecureSkipVerify? [fasle]: ``` diff --git a/cli.go b/cli.go index 8598b6f..1e33396 100644 --- a/cli.go +++ b/cli.go @@ -158,6 +158,38 @@ func PromptForConfiguration() Config { config.Sensors = append(config.Sensors, s) } + fmt.Println("Write data to an Influx database?") + fmt.Print("[Y/n]: ") + choice := ReadInput(reader, "y") + if strings.ToLower(choice)[0] == 'y' { + fmt.Print("Influx address [http://influx:8086]: ") + config.Influx.Addr = ReadInput(reader, "http://influx:8086") + + fmt.Print("Influx Username []: ") + config.Influx.Username = ReadInput(reader, "") + + fmt.Print("Influx Password []: ") + config.Influx.Password = ReadInput(reader, "") + + fmt.Print("Influx UserAgent [InfluxDBClient]: ") + config.Influx.UserAgent = ReadInput(reader, "InfluxDBClient") + + fmt.Print("Influx timeout (in seconds) [30]: ") + config.Influx.Timeout, err = strconv.ParseFloat(ReadInput(reader, "30"), 64) + if err != nil { + panic(err) + } + + fmt.Print("Influx database []: ") + config.Influx.Database = ReadInput(reader, "") + + fmt.Print("Enable InsecureSkipVerify? [fasle]: ") + config.Influx.InsecureSkipVerify, err = strconv.ParseBool(ReadInput(reader, "false")) + if err != nil { + panic(err) + } + } + return config } diff --git a/config.go b/config.go index ebe3b91..ea83adc 100644 --- a/config.go +++ b/config.go @@ -10,6 +10,17 @@ import ( "gopkg.in/yaml.v2" ) +// Influx defines an Influx database configuration +type Influx struct { + Addr string `json:"string" yaml:"addr"` + Username string `json:"username" yaml:"username"` + Password string `json:"-" yaml:"password"` + UserAgent string `json:"useragent" yaml:"useragent"` + Timeout float64 `json:"timeout" yaml:"timeout"` + InsecureSkipVerify bool `json:"insecureskipverify" yaml:"insecureskipverify"` + Database string `json:"database" yaml:"database"` +} + // Sensor defines configuration for a temperature sensor. type Sensor struct { ID string `json:"id" yaml:"id"` @@ -31,6 +42,7 @@ type Config struct { BaseURL string `yaml:"baseurl"` ListenAddr string `yaml:"listenaddr"` DisplayFahrenheit bool `yaml:"displayfahrenheit"` + Influx Influx `yaml:"influx"` } var configFilePath string diff --git a/config_test.go b/config_test.go index 66c6d77..4eb03af 100644 --- a/config_test.go +++ b/config_test.go @@ -7,25 +7,27 @@ import ( ) func Test_LoadConfig(t *testing.T) { - testSensor := Sensor{ - ID: "28-000008083108", - Alias: "fermenter", - HighTemp: 8, - LowTemp: 4, - HeatGPIO: 5, - HeatInvert: true, - HeatMinutes: 5, - CoolGPIO: 17, - CoolInvert: false, - CoolMinutes: 10, - Verbose: true, - } testConfig := Config{ - Sensors: []Sensor{testSensor}, + Sensors: []Sensor{ + Sensor{ + ID: "28-000008083108", + Alias: "fermenter", + HighTemp: 8, + LowTemp: 4, + HeatGPIO: 5, + HeatInvert: true, + HeatMinutes: 5, + CoolGPIO: 17, + CoolInvert: false, + CoolMinutes: 10, + Verbose: true, + }, + }, BaseURL: "https://foo.bar", ListenAddr: "127.0.0.1:8080", DisplayFahrenheit: true, + Influx: Influx{Addr: "http://foo:8086"}, } loadedConfig, err := LoadConfig("tests/test_config.yml") diff --git a/influx.go b/influx.go new file mode 100644 index 0000000..9fdd97e --- /dev/null +++ b/influx.go @@ -0,0 +1,46 @@ +package main + +import ( + "time" + + client "github.com/influxdata/influxdb/client/v2" +) + +// WriteStateToInflux writes a State object to an Influx database +func WriteStateToInflux(s State, config Influx) error { + + c, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: config.Addr, + Username: config.Username, + Password: config.Password, + UserAgent: config.UserAgent, + Timeout: time.Duration(config.Timeout * 1000000000), + InsecureSkipVerify: config.InsecureSkipVerify, + }) + if err != nil { + return err + } + defer c.Close() + + bp, err := client.NewBatchPoints(client.BatchPointsConfig{ + Database: config.Database, + Precision: "s", + }) + if err != nil { + return err + } + + tags := map[string]string{"alias": s.Alias} + fields := map[string]interface{}{"value": s.Temp} + pt, err := client.NewPoint("temperature", tags, fields, s.When) + if err != nil { + return err + } + + bp.AddPoint(pt) + if err := c.Write(bp); err != nil { + return err + } + + return nil +} diff --git a/tests/test_config.yml b/tests/test_config.yml index 5b6d6b4..3cd901f 100644 --- a/tests/test_config.yml +++ b/tests/test_config.yml @@ -13,3 +13,5 @@ sensors: baseurl: https://foo.bar listenaddr: 127.0.0.1:8080 displayfahrenheit: true +influx: + addr: http://foo:8086 diff --git a/thermostat.go b/thermostat.go index 172fe7e..fd01673 100644 --- a/thermostat.go +++ b/thermostat.go @@ -216,6 +216,10 @@ func RunThermostat(path string, sc chan<- State, wg *sync.WaitGroup) { default: break } + + if config.Influx.Addr != "" { + go WriteStateToInflux(states[v.ID], config.Influx) + } } }