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