package config import ( "fmt" "net/url" "time" "github.com/volker-raschek/flucky/pkg/internal/format" "github.com/volker-raschek/flucky/pkg/rgbled" "github.com/volker-raschek/flucky/pkg/sensor" "github.com/volker-raschek/flucky/pkg/types" uuid "github.com/satori/go.uuid" ) // 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"` } // 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.ID { rgbLED.DeviceID = c.Device.ID } // 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 ID is a valid UUID string if !validUUID.MatchString(sensor.ID) { sensor.ID = uuid.NewV4().String() } // check if sensor name and sensor uuid already exists for _, s := range c.Sensors { if s.Name == sensor.Name { return fmt.Errorf("Sensor %v already exists", s.Name) } if s.ID == sensor.ID { return fmt.Errorf("Sensor %v with UUID %v already exists", s.Name, s.ID) } 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.Name) } } } // check if sensor has a valid tick time if _, err := time.ParseDuration(sensor.TickDuration); err != nil { return fmt.Errorf("Can not parse tick duration: %v", sensor.TickDuration) } // check if sensor has a valid device id if sensor.DeviceID != c.Device.ID { sensor.DeviceID = c.Device.ID } // 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.Name == name { sensor.Enabled = false found = true break } // remove machted uuid if validUUID.MatchString(name) && sensor.ID == name { sensor.Enabled = 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.Name == name { sensor.Enabled = true found = true break } // remove machted uuid if validUUID.MatchString(name) && sensor.ID == name { sensor.Enabled = 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.Enabled { cachedSensors = append(cachedSensors, sensor) } } return c.convertSensors(cachedSensors) case DISABLED: for _, sensor := range sensors { if !sensor.Enabled { 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.ID: configHumiditySensors[s.ID] = s case s.Name: configHumiditySensors[s.ID] = 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.Enabled { cachedSensors = append(cachedSensors, sensor) } } return c.convertSensors(cachedSensors) case DISABLED: for _, sensor := range sensors { if !sensor.Enabled { 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.ID: configPressureSensors[s.ID] = s case s.Name: configPressureSensors[s.ID] = 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) } // GetSensorByID returns a sensor matched by his id. If no sensor has this id, // the function returns nil func (c *Configuration) GetSensorByID(id string) *types.Sensor { for _, sensor := range c.Sensors { if sensor.ID == id { return sensor } } return nil } // 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.Enabled { cachedSensors = append(cachedSensors, sensor) } } return c.convertSensors(cachedSensors) case DISABLED: for _, sensor := range c.Sensors { if !sensor.Enabled { 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.Enabled { cachedSensors = append(cachedSensors, sensor) } } return c.convertSensors(cachedSensors) case DISABLED: for _, sensor := range sensors { if !sensor.Enabled { 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.ID: configTemperatureSensors[s.ID] = s case s.Name: configTemperatureSensors[s.ID] = 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.Name == name { c.Sensors = append(c.Sensors[:i], c.Sensors[i+1:]...) return nil } // remove machted uuid if validUUID.MatchString(name) && sensor.ID == 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.Name == oldName || sensor.ID == oldName { sensor.Name = 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.Model { 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.Model]; 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.Model]; 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.Model]; ok { temperatureSensors = append(temperatureSensors, s) } } return temperatureSensors }