feat(pkg/sensor): new support for sensor bme280
This commit is contained in:
		| @@ -13,14 +13,16 @@ import ( | ||||
| ) | ||||
|  | ||||
| var humiditySensorModels = map[types.SensorModel]types.SensorModel{ | ||||
| 	types.DHT11: types.DHT11, | ||||
| 	types.DHT22: types.DHT22, | ||||
| 	types.DHT11:  types.DHT11, | ||||
| 	types.DHT22:  types.DHT22, | ||||
| 	types.BME280: types.BME280, | ||||
| } | ||||
|  | ||||
| var temperatureSensorModels = map[types.SensorModel]types.SensorModel{ | ||||
| 	types.DHT11:   types.DHT11, | ||||
| 	types.DHT22:   types.DHT22, | ||||
| 	types.DS18B20: types.DS18B20, | ||||
| 	types.BME280:  types.BME280, | ||||
| } | ||||
|  | ||||
| // Configuration of flucky | ||||
| @@ -82,9 +84,10 @@ func (c *Configuration) AddSensor(sensor *types.Sensor) error { | ||||
| 			return fmt.Errorf("Sensor %v with UUID %v already exists", s.SensorName, s.SensorID) | ||||
| 		} | ||||
|  | ||||
| 		if *sensor.WireID != "" && | ||||
| 			*s.WireID == *sensor.WireID { | ||||
| 			return fmt.Errorf("Sensor with 1wire-id %v already exists as %v", *s.WireID, s.SensorName) | ||||
| 		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) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -260,8 +263,6 @@ func (c *Configuration) GetHumiditySensorsByName(names []string) []sensor.Sensor | ||||
| 			switch name { | ||||
| 			case s.SensorID: | ||||
| 				configHumiditySensors[s.SensorID] = s | ||||
| 			case *s.WireID: | ||||
| 				configHumiditySensors[s.SensorID] = s | ||||
| 			case s.SensorName: | ||||
| 				configHumiditySensors[s.SensorID] = s | ||||
| 			} | ||||
| @@ -381,8 +382,6 @@ func (c *Configuration) GetTemperatureSensorsByName(names []string) []sensor.Sen | ||||
| 			switch name { | ||||
| 			case s.SensorID: | ||||
| 				configTemperatureSensors[s.SensorID] = s | ||||
| 			case *s.WireID: | ||||
| 				configTemperatureSensors[s.SensorID] = s | ||||
| 			case s.SensorName: | ||||
| 				configTemperatureSensors[s.SensorID] = s | ||||
| 			} | ||||
| @@ -464,6 +463,10 @@ func (c *Configuration) convertSensors(sensors []*types.Sensor) []sensor.Sensor | ||||
|  | ||||
| 	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, | ||||
|   | ||||
| @@ -16,7 +16,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| // Start the daemon | ||||
| func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, logger logger.Logger) { | ||||
| func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, logger logger.Logger) { | ||||
|  | ||||
| 	// Info | ||||
| 	logger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String()) | ||||
| @@ -33,7 +33,7 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress | ||||
| 	ctx := context.Background() | ||||
| 	childContext, cancel := context.WithCancel(ctx) | ||||
|  | ||||
| 	logfile := logfile.New(cnf.Device.Logfile) | ||||
| 	measuredValuesLogfile := logfile.New(cnf.Device.Logfile) | ||||
|  | ||||
| 	measuredValuesCache := make([]types.MeasuredValue, 0) | ||||
|  | ||||
| @@ -66,7 +66,7 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress | ||||
| 				logger.Error("Can not turn on blue info light: %v", err) | ||||
| 			} | ||||
|  | ||||
| 			err = logfile.Append(compression, measuredValuesCache) | ||||
| 			err = logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache) | ||||
| 			if err != nil { | ||||
|  | ||||
| 				err = rgbled.Error(rgbLEDs) | ||||
| @@ -92,8 +92,8 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress | ||||
| 				logger.Error("Can not turn on red info light: %v", err) | ||||
| 			} | ||||
|  | ||||
| 			logger.Warn("Save remaining data from the cache: %v", len(measuredValuesCache)) | ||||
| 			err = logfile.Append(compression, measuredValuesCache) | ||||
| 			logger.Warn("Save remaining data from the cache") | ||||
| 			err = logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache) | ||||
| 			if err != nil { | ||||
| 				logger.Fatal("%v", err) | ||||
| 			} | ||||
|   | ||||
| @@ -14,28 +14,6 @@ type csvLogfile struct { | ||||
| 	logfile string | ||||
| } | ||||
|  | ||||
| func (cl *csvLogfile) Append(compression bool, measuredValues []types.MeasuredValue) error { | ||||
|  | ||||
| 	allMeasuredValues, err := cl.Read() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	allMeasuredValues = append(allMeasuredValues, measuredValues...) | ||||
|  | ||||
| 	if compression { | ||||
| 		allMeasuredValues = Compression(allMeasuredValues) | ||||
| 	} | ||||
|  | ||||
| 	err = cl.Write(allMeasuredValues) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (cl *csvLogfile) Read() ([]types.MeasuredValue, error) { | ||||
| 	if _, err := os.Stat(cl.logfile); os.IsNotExist(err) { | ||||
| 		return nil, fmt.Errorf("%v: %v", errorLogfileNotFound, cl.logfile) | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import ( | ||||
| ) | ||||
|  | ||||
| type Logfile interface { | ||||
| 	Append(compression bool, measuredValues []types.MeasuredValue) error | ||||
| 	Read() ([]types.MeasuredValue, error) | ||||
| 	Write(measuredValues []types.MeasuredValue) error | ||||
| } | ||||
|   | ||||
| @@ -17,28 +17,6 @@ type jsonLogfile struct { | ||||
| 	logfile string | ||||
| } | ||||
|  | ||||
| func (jl *jsonLogfile) Append(compression bool, measuredValues []types.MeasuredValue) error { | ||||
|  | ||||
| 	allMeasuredValues, err := jl.Read() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	allMeasuredValues = append(allMeasuredValues, measuredValues...) | ||||
|  | ||||
| 	if compression { | ||||
| 		allMeasuredValues = Compression(allMeasuredValues) | ||||
| 	} | ||||
|  | ||||
| 	err = jl.Write(allMeasuredValues) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (jl *jsonLogfile) Read() ([]types.MeasuredValue, error) { | ||||
|  | ||||
| 	if _, err := os.Stat(jl.logfile); os.IsNotExist(err) { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package logfile | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
| 	"path/filepath" | ||||
| 	"sort" | ||||
| 	"time" | ||||
| @@ -9,7 +10,35 @@ import ( | ||||
| ) | ||||
|  | ||||
| // var validUUID = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$") | ||||
| var timeFormat = time.RFC3339 | ||||
| var timeFormat = "2006-01-02T15:04:05.999999Z07:00" | ||||
|  | ||||
| func Append(logfile Logfile, compression bool, round float64, measuredValues []types.MeasuredValue) error { | ||||
|  | ||||
| 	if round != 0 { | ||||
| 		for _, measuredValue := range measuredValues { | ||||
| 			measuredValue.SetValue(math.Round(measuredValue.GetValue()/round) * round) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	allMeasuredValues, err := logfile.Read() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	allMeasuredValues = append(allMeasuredValues, measuredValues...) | ||||
|  | ||||
| 	if compression { | ||||
| 		allMeasuredValues = Compression(allMeasuredValues) | ||||
| 	} | ||||
|  | ||||
| 	err = logfile.Write(allMeasuredValues) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Compression the measured values. The system checks whether the measured values | ||||
| // of the same type correspond to those of the predecessor. If this is the case, | ||||
|   | ||||
							
								
								
									
										112
									
								
								pkg/sensor/bme280.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								pkg/sensor/bme280.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| package sensor | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/d2r2/go-bsbmp" | ||||
| 	"github.com/d2r2/go-i2c" | ||||
| 	"github.com/d2r2/go-logger" | ||||
| 	"github.com/go-flucky/flucky/pkg/types" | ||||
| 	uuid "github.com/satori/go.uuid" | ||||
| ) | ||||
|  | ||||
| // BME280 is a sensor to measure humidity and temperature. | ||||
| type BME280 struct { | ||||
| 	*types.Sensor | ||||
| } | ||||
|  | ||||
| // GetSensorModel returns the sensor model | ||||
| func (s *BME280) GetSensorModel() types.SensorModel { | ||||
| 	return s.Sensor.SensorModel | ||||
| } | ||||
|  | ||||
| // Read measured values | ||||
| func (s *BME280) Read() ([]types.MeasuredValue, error) { | ||||
|  | ||||
| 	// Create new connection to i2c-bus on 1 line with address 0x76. | ||||
| 	// Use i2cdetect utility to find device address over the i2c-bus | ||||
| 	i2c, err := i2c.NewI2C(*s.I2CAddress, *s.I2CBus) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	defer i2c.Close() | ||||
|  | ||||
| 	logger.ChangePackageLogLevel("i2c", logger.InfoLevel) | ||||
|  | ||||
| 	sensor, err := bsbmp.NewBMP(bsbmp.BME280, i2c) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	logger.ChangePackageLogLevel("bsbmp", logger.InfoLevel) | ||||
|  | ||||
| 	temperatureValue, err := sensor.ReadTemperatureC(bsbmp.ACCURACY_STANDARD) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// p, err := sensor.ReadPressurePa(bsbmp.ACCURACY_STANDARD) | ||||
| 	// if err != nil { | ||||
| 	// 	log.Fatal(err) | ||||
| 	// } | ||||
|  | ||||
| 	_, humidityValue, err := sensor.ReadHumidityRH(bsbmp.ACCURACY_STANDARD) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	measuredValues := []types.MeasuredValue{ | ||||
| 		&types.Humidity{ | ||||
| 			HumidityID:       uuid.NewV4().String(), | ||||
| 			HumidityValue:    float64(humidityValue), | ||||
| 			HumidityFromDate: time.Now(), | ||||
| 			HumidityTillDate: time.Now(), | ||||
| 			SensorID:         s.SensorID, | ||||
| 		}, | ||||
| 		&types.Temperature{ | ||||
| 			TemperatureID:       uuid.NewV4().String(), | ||||
| 			TemperatureValue:    float64(temperatureValue), | ||||
| 			TemperatureFromDate: time.Now(), | ||||
| 			TemperatureTillDate: time.Now(), | ||||
| 			SensorID:            s.SensorID, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	return measuredValues, nil | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	if wg != nil { | ||||
| 		defer wg.Done() | ||||
| 	} | ||||
|  | ||||
| 	measuredValues, err := s.Read() | ||||
| 	if err != nil { | ||||
| 		errorChannel <- err | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	measuredValuesChannel <- measuredValues | ||||
|  | ||||
| } | ||||
|  | ||||
| // 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) { | ||||
| 	for { | ||||
| 		select { | ||||
| 		case <-ctx.Done(): | ||||
| 			errorChannel <- fmt.Errorf("%v: Context closed: %v", s.SensorName, ctx.Err()) | ||||
| 			return | ||||
| 		default: | ||||
| 			s.ReadChannel(measuredValuesChannel, errorChannel, nil) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -45,6 +45,10 @@ func (h *Humidity) GetMeasuredValueType() MeasuredValueType { | ||||
| 	return MeasuredValueTypeHumidity | ||||
| } | ||||
|  | ||||
| func (h *Humidity) SetValue(value float64) { | ||||
| 	h.HumidityValue = value | ||||
| } | ||||
|  | ||||
| func (h *Humidity) SetTillDate(date time.Time) { | ||||
| 	h.HumidityTillDate = date | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,7 @@ type MeasuredValue interface { | ||||
| 	GetCreationDate() *time.Time | ||||
| 	GetUpdateDate() *time.Time | ||||
|  | ||||
| 	SetValue(value float64) | ||||
| 	SetTillDate(date time.Time) | ||||
| 	SetCreationDate(date *time.Time) | ||||
| 	SetUpdateDate(date *time.Time) | ||||
|   | ||||
| @@ -13,6 +13,8 @@ type Sensor struct { | ||||
| 	SensorName        string      `json:"sensor_name" xml:"sensor_name"` | ||||
| 	SensorLocation    string      `json:"sensor_location" xml:"sensor_location"` | ||||
| 	WireID            *string     `json:"wire_id" xml:"wire_id"` | ||||
| 	I2CBus            *int        `json:"i2c_bus" xml:"i2c_bus"` | ||||
| 	I2CAddress        *uint8      `json:"i2c_address" xml:"i2c_address"` | ||||
| 	GPIONumber        *GPIO       `json:"gpio_number" xml:"gpio_number"` | ||||
| 	SensorModel       SensorModel `json:"sensor_model" xml:"sensor_model"` | ||||
| 	SensorEnabled     bool        `json:"sensor_enabled" xml:"sensor_enabled"` | ||||
| @@ -46,6 +48,9 @@ func (s *Sensor) Name() string { | ||||
| 		return s.SensorName | ||||
| 	} else if s.WireID != nil { | ||||
| 		return *s.WireID | ||||
| 	} else if s.I2CAddress != nil && | ||||
| 		s.I2CBus != nil { | ||||
| 		return fmt.Sprintf("%v/%v", *s.I2CBus, *s.I2CAddress) | ||||
| 	} | ||||
| 	return s.SensorID | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,8 @@ import "fmt" | ||||
| type SensorModel string | ||||
|  | ||||
| const ( | ||||
| 	DHT11   SensorModel = "DHT11" | ||||
| 	BME280  SensorModel = "BME280" | ||||
| 	DHT11               = "DHT11" | ||||
| 	DHT22               = "DHT22" | ||||
| 	DS18B20             = "DS18B20" | ||||
| ) | ||||
| @@ -13,6 +14,8 @@ const ( | ||||
| // SelectSensorModel converts a string into a constant | ||||
| func SelectSensorModel(model string) (SensorModel, error) { | ||||
| 	switch model { | ||||
| 	case "BME280": | ||||
| 		return BME280, nil | ||||
| 	case "DHT11": | ||||
| 		return DHT11, nil | ||||
| 	case "DHT22": | ||||
|   | ||||
| @@ -47,6 +47,10 @@ func (t *Temperature) GetMeasuredValueType() MeasuredValueType { | ||||
| 	return MeasuredValueTypeTemperature | ||||
| } | ||||
|  | ||||
| func (t *Temperature) SetValue(value float64) { | ||||
| 	t.TemperatureValue = value | ||||
| } | ||||
|  | ||||
| func (t *Temperature) SetTillDate(date time.Time) { | ||||
| 	t.TemperatureTillDate = date | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user