gobot.io/x/gobot@v1.16.0/drivers/i2c/yl40_driver.go (about) 1 package i2c 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "gobot.io/x/gobot" 10 "gobot.io/x/gobot/drivers/aio" 11 ) 12 13 // All address pins are connected to ground. 14 const yl40DefaultAddress = 0x48 15 16 const yl40Debug = false 17 18 type YL40Pin string 19 20 const ( 21 // brightness sensor, high brightness - low raw value, scaled to 0..1000 (high brightness - high value) 22 YL40Bri YL40Pin = "brightness" 23 // temperature sensor, high temperature - low raw value, scaled to °C 24 YL40Temp YL40Pin = "temperature" 25 // wired to AOUT, scaled to voltage 3.3V 26 YL40AIN2 YL40Pin = "analog input AIN2" 27 // adjustable resistor, turn clockwise will lower the raw value, scaled to -100..+100% (clockwise) 28 YL40Poti YL40Pin = "potentiometer" 29 YL40AOUT YL40Pin = "analog output" 30 ) 31 32 const ( 33 // the LED light is visible above ~1.7V 34 yl40LedDefaultVal = 1.7 35 // default refresh rate, set to zero (cyclic reading deactivated) 36 yl40DefaultRefresh = 0 37 ) 38 39 type yl40Sensor struct { 40 interval time.Duration 41 scaler func(input int) (value float64) 42 } 43 44 type yl40Config struct { 45 sensors map[YL40Pin]*yl40Sensor 46 aOutScaler func(input float64) (value int) 47 } 48 49 var yl40Pins = map[YL40Pin]string{ 50 YL40Bri: "s.0", 51 YL40Temp: "s.1", 52 YL40AIN2: "s.2", 53 YL40Poti: "s.3", 54 YL40AOUT: "aOut.0", 55 } 56 57 // YL40Driver is a Gobot i2c bus driver for the YL-40 module with light dependent resistor (LDR), thermistor (NTC) 58 // and an potentiometer, one additional analog input and one analog output with an connected LED. 59 // The module is based on PCF8591 with 4xADC, 1xDAC. For detailed documentation refer to PCF8591Driver. 60 // 61 // All values are linear scaled to 3.3V by default. This can be changed, see example "tinkerboard_yl40.go". 62 // 63 // This driver was tested with Tinkerboard and this board with temperature & brightness sensor: 64 // https://www.makershop.de/download/YL_40_yl40.pdf 65 // 66 type YL40Driver struct { 67 *PCF8591Driver 68 conf yl40Config 69 70 aBri *aio.AnalogSensorDriver 71 aTemp *aio.TemperatureSensorDriver 72 aAIN2 *aio.AnalogSensorDriver 73 aPoti *aio.AnalogSensorDriver 74 aOut *aio.AnalogActuatorDriver 75 } 76 77 // NewYL40Driver creates a new driver with specified i2c interface 78 // Params: 79 // conn Connector - the Adaptor to use with this Driver 80 // 81 // Optional parameters: 82 // refer to PCF8591Driver for i2c specific options 83 // refer to TemperatureSensorDriver for temperature sensor specific options 84 // refer to AnalogSensorDriver for analog input specific options 85 // refer to AnalogActuatorDriver for analog output specific options 86 // 87 func NewYL40Driver(a Connector, options ...func(Config)) *YL40Driver { 88 options = append(options, WithAddress(yl40DefaultAddress)) 89 pcf := NewPCF8591Driver(a, options...) 90 91 ntc := aio.TemperatureSensorNtcConf{TC0: 25, R0: 10000.0, B: 3950} //Ohm, R25=10k, B=3950 92 defTempScaler := aio.TemperatureSensorNtcScaler(255, 1000, true, ntc) 93 94 defConf := yl40Config{ 95 sensors: map[YL40Pin]*yl40Sensor{ 96 YL40Bri: { 97 interval: yl40DefaultRefresh, 98 scaler: aio.AnalogSensorLinearScaler(0, 255, 1000, 0), 99 }, 100 YL40Temp: { 101 interval: yl40DefaultRefresh, 102 scaler: defTempScaler, 103 }, 104 YL40AIN2: { 105 interval: yl40DefaultRefresh, 106 scaler: aio.AnalogSensorLinearScaler(0, 255, 0, 3.3), 107 }, 108 YL40Poti: { 109 interval: yl40DefaultRefresh, 110 scaler: aio.AnalogSensorLinearScaler(0, 255, 100, -100), 111 }, 112 }, 113 aOutScaler: aio.AnalogActuatorLinearScaler(0, 3.3, 0, 255), 114 } 115 116 y := &YL40Driver{ 117 PCF8591Driver: pcf, 118 conf: defConf, 119 } 120 121 y.SetName(gobot.DefaultName("YL-40")) 122 123 for _, option := range options { 124 option(y) 125 } 126 127 // initialize analog drivers 128 y.aBri = aio.NewAnalogSensorDriver(pcf, yl40Pins[YL40Bri], y.conf.sensors[YL40Bri].interval) 129 y.aTemp = aio.NewTemperatureSensorDriver(pcf, yl40Pins[YL40Temp], y.conf.sensors[YL40Temp].interval) 130 y.aAIN2 = aio.NewAnalogSensorDriver(pcf, yl40Pins[YL40AIN2], y.conf.sensors[YL40AIN2].interval) 131 y.aPoti = aio.NewAnalogSensorDriver(pcf, yl40Pins[YL40Poti], y.conf.sensors[YL40Poti].interval) 132 y.aOut = aio.NewAnalogActuatorDriver(pcf, yl40Pins[YL40AOUT]) 133 134 // set input scalers 135 y.aBri.SetScaler(y.conf.sensors[YL40Bri].scaler) 136 y.aTemp.SetScaler(y.conf.sensors[YL40Temp].scaler) 137 y.aAIN2.SetScaler(y.conf.sensors[YL40AIN2].scaler) 138 y.aPoti.SetScaler(y.conf.sensors[YL40Poti].scaler) 139 140 // set output scaler 141 y.aOut.SetScaler(y.conf.aOutScaler) 142 143 return y 144 } 145 146 // WithYL40Interval option sets the interval for refresh of given pin in YL40 driver 147 func WithYL40Interval(pin YL40Pin, val time.Duration) func(Config) { 148 return func(c Config) { 149 y, ok := c.(*YL40Driver) 150 if ok { 151 if sensor, ok := y.conf.sensors[pin]; ok { 152 sensor.interval = val 153 } 154 } else if yl40Debug { 155 log.Printf("trying to set interval for '%s' refresh for non-YL40Driver %v", pin, c) 156 } 157 } 158 } 159 160 // WithYL40InputScaler option sets the input scaler of given input pin in YL40 driver 161 func WithYL40InputScaler(pin YL40Pin, scaler func(input int) (value float64)) func(Config) { 162 return func(c Config) { 163 y, ok := c.(*YL40Driver) 164 if ok { 165 if sensor, ok := y.conf.sensors[pin]; ok { 166 sensor.scaler = scaler 167 } 168 } else if yl40Debug { 169 log.Printf("trying to set input scaler for '%s' for non-YL40Driver %v", pin, c) 170 } 171 } 172 } 173 174 // WithYL40OutputScaler option sets the output scaler in YL40 driver 175 func WithYL40OutputScaler(scaler func(input float64) (value int)) func(Config) { 176 return func(c Config) { 177 y, ok := c.(*YL40Driver) 178 if ok { 179 y.conf.aOutScaler = scaler 180 } else if yl40Debug { 181 log.Printf("trying to set output scaler for '%s' for non-YL40Driver %v", YL40AOUT, c) 182 } 183 } 184 } 185 186 // Start initializes the driver 187 func (y *YL40Driver) Start() (err error) { 188 // must be the first one 189 if err := y.PCF8591Driver.Start(); err != nil { 190 return err 191 } 192 if err := y.aBri.Start(); err != nil { 193 return err 194 } 195 if err := y.aTemp.Start(); err != nil { 196 return err 197 } 198 if err := y.aAIN2.Start(); err != nil { 199 return err 200 } 201 if err := y.aPoti.Start(); err != nil { 202 return err 203 } 204 if err := y.aOut.Start(); err != nil { 205 return err 206 } 207 return y.Write(yl40LedDefaultVal) 208 } 209 210 // Halt stops the driver 211 func (y *YL40Driver) Halt() (err error) { 212 // we try halt on each device, not stopping on the first error 213 var errors []string 214 if err := y.aBri.Halt(); err != nil { 215 errors = append(errors, err.Error()) 216 } 217 if err := y.aTemp.Halt(); err != nil { 218 errors = append(errors, err.Error()) 219 } 220 if err := y.aAIN2.Halt(); err != nil { 221 errors = append(errors, err.Error()) 222 } 223 if err := y.aPoti.Halt(); err != nil { 224 errors = append(errors, err.Error()) 225 } 226 if err := y.aOut.Halt(); err != nil { 227 errors = append(errors, err.Error()) 228 } 229 // must be the last one 230 if err := y.PCF8591Driver.Halt(); err != nil { 231 errors = append(errors, err.Error()) 232 } 233 if len(errors) > 0 { 234 return fmt.Errorf("Halt the driver %s", strings.Join(errors, ", ")) 235 } 236 return nil 237 } 238 239 // Read returns the current reading from the given pin of the driver 240 // For the analog output pin the last written value is returned 241 func (y *YL40Driver) Read(pin YL40Pin) (val float64, err error) { 242 switch pin { 243 case YL40Bri: 244 return y.aBri.ReadValue() 245 case YL40Temp: 246 return y.aTemp.ReadValue() 247 case YL40AIN2: 248 return y.aAIN2.ReadValue() 249 case YL40Poti: 250 return y.aPoti.ReadValue() 251 case YL40AOUT: 252 return y.aOut.Value(), nil 253 default: 254 return 0, fmt.Errorf("Analog reading from pin '%s' not supported", pin) 255 } 256 } 257 258 // ReadBrightness returns the current reading from brightness pin of the driver 259 func (y *YL40Driver) ReadBrightness() (val float64, err error) { 260 return y.Read(YL40Bri) 261 } 262 263 // ReadTemperature returns the current reading from temperature pin of the driver 264 func (y *YL40Driver) ReadTemperature() (val float64, err error) { 265 return y.Read(YL40Temp) 266 } 267 268 // ReadAIN2 returns the current reading from analog input pin 2 pin of the driver 269 func (y *YL40Driver) ReadAIN2() (val float64, err error) { 270 return y.Read(YL40AIN2) 271 } 272 273 // ReadPotentiometer returns the current reading from potentiometer pin of the driver 274 func (y *YL40Driver) ReadPotentiometer() (val float64, err error) { 275 return y.Read(YL40Poti) 276 } 277 278 // Value returns the last read or written value from the given pin of the driver 279 func (y *YL40Driver) Value(pin YL40Pin) (val float64, err error) { 280 switch pin { 281 case YL40Bri: 282 return y.aBri.Value(), nil 283 case YL40Temp: 284 return y.aTemp.Value(), nil 285 case YL40AIN2: 286 return y.aAIN2.Value(), nil 287 case YL40Poti: 288 return y.aPoti.Value(), nil 289 case YL40AOUT: 290 return y.aOut.Value(), nil 291 default: 292 return 0, fmt.Errorf("Get analog value from pin '%s' not supported", pin) 293 } 294 } 295 296 // Brightness returns the last read brightness of the driver 297 func (y *YL40Driver) Brightness() (val float64, err error) { 298 return y.Value(YL40Bri) 299 } 300 301 // Temperature returns the last read temperature of the driver 302 func (y *YL40Driver) Temperature() (val float64, err error) { 303 return y.Value(YL40Temp) 304 } 305 306 // AIN2 returns the last read analog input value of the driver 307 func (y *YL40Driver) AIN2() (val float64, err error) { 308 return y.Value(YL40AIN2) 309 } 310 311 // Potentiometer returns the last read potentiometer value of the driver 312 func (y *YL40Driver) Potentiometer() (val float64, err error) { 313 return y.Value(YL40Poti) 314 } 315 316 // AOUT returns the last written value of the driver 317 func (y *YL40Driver) AOUT() (val float64, err error) { 318 return y.Value(YL40AOUT) 319 } 320 321 // Write writes the given value to the analog output 322 func (y *YL40Driver) Write(val float64) (err error) { 323 return y.aOut.Write(val) 324 }