class GroveTemperatureHumiditySensorSHT3x(object): def __init__(self, address=0x45, bus=None): self.address = address # I2C bus self.bus = Bus(bus) def read(self): # high repeatability, clock stretching disabled self.bus.write_i2c_block_data(self.address, 0x24, [0x00]) # measurement duration < 16 ms time.sleep(0.016) # read 6 bytes back # Temp MSB, Temp LSB, Temp CRC, Humididty MSB, Humidity LSB, Humidity CRC data = self.bus.read_i2c_block_data(0x45, 0x00, 6) temperature = data[0] * 256 + data[1] celsius = -45 + (175 * temperature / 65535.0) humidity = 100 * (data[3] * 256 + data[4]) / 65535.0 if data[2] != CRC(data[:2]): raise RuntimeError("temperature CRC mismatch") if data[5] != CRC(data[3:5]): raise RuntimeError("humidity CRC mismatch") return celsius, humidity
class GroveTemperatureHumidityAHT20(object): def __init__(self, address=0x38, bus=None): self.address = address # I2C bus self.bus = Bus(bus) def read(self): self.bus.write_i2c_block_data(self.address, 0x00, [0xac, 0x33, 0x00]) # measurement duration < 16 ms time.sleep(0.016) data = self.bus.read_i2c_block_data(self.address, 0x00, 6) humidity = data[1] humidity <<= 8 humidity += data[2] humidity <<= 4 humidity += (data[3] >> 4) humidity /= 1048576.0 humidity *= 100 temperature = data[3] & 0x0f temperature <<= 8 temperature += data[4] temperature <<= 8 temperature += data[5] temperature = temperature / 1048576.0 * 200.0 - 50.0 # Convert to Celsius return temperature, humidity
class Motor(object): __MotorSpeedSet = 0x82 __PWMFrequenceSet = 0x84 __DirectionSet = 0xaa __MotorSetA = 0xa1 __MotorSetB = 0xa5 __Nothing = 0x01 __EnableStepper = 0x1a __UnenableStepper = 0x1b __Stepernu = 0x1c I2CAddr = 0x0f #Set the address of the I2CMotorDriver SPEED_MAX = 100 def __init__(self, address=0x0f): #I2C Port - Grove - I2C Motor Driver V1.3 self.I2CAddr = address self.bus = Bus() self.motor = [null, DCMotor(), DCMotor] def __del__(self): self.set_speed(0, 0) #Maps speed from 0-100 to 0-255 def _map_vals(self, value, leftMin, leftMax, rightMin, rightMax): #http://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another # Figure out how 'wide' each range is leftSpan = leftMax - leftMin rightSpan = rightMax - rightMin # Convert the left range into a 0-1 range (float) valueScaled = float(value - leftMin) / float(leftSpan) # Convert the 0-1 range into a value in the right range. return int(rightMin + (valueScaled * rightSpan)) def update(self): self.set_dir(self.motor[1].clockwise, self.motor[2].clockwise) self.set_speed(self.motor[1].speed, self.motor[2].speed) #Set motor speed def set_speed(self, speed1=0, speed2=0): s1 = self._map_vals(speed1, 0, 100, 0, 255) s2 = self._map_vals(speed2, 0, 100, 0, 255) self.bus.write_i2c_block_data(self.I2CAddr, self.__MotorSpeedSet, [s1, s2]) time.sleep(.02) #Set motor direction def set_dir(self, clock_wise1=True, clock_wise2=True): dir1 = 0b10 if clock_wise1 else 0b01 dir2 = 0b10 if clock_wise2 else 0b01 dir = (dir2 << 2) | dir1 self.bus.write_i2c_block_data(self.I2CAddr, self.__DirectionSet, [dir, 0]) time.sleep(.02)
class I2C_Station: def __init__(self, weather_sensor_address=Config.I2C_WEATHER_SENSOR_ADDRESS, bus=None): self.weather_sensor_address = weather_sensor_address self.bus = Bus(bus) if Config.ENABLE_POWERGAUGE: self.powergauge_module = LC709203F( board.I2C(), address=Config.I2C_POWERGAUGE_ADDRESS) def CRC(self, data): crc = 0xff for s in data: crc ^= s for _ in range(8): if crc & 0x80: crc <<= 1 crc ^= 0x131 else: crc <<= 1 return crc def read_weather_data(self): self.bus.write_i2c_block_data(self.weather_sensor_address, 0x24, [0x00]) time.sleep(0.016) data = self.bus.read_i2c_block_data(self.weather_sensor_address, 0x00, 6) temperature = data[0] * 256 + data[1] celsius = -45 + (175 * temperature / 65535.0) humidity = 100 * (data[3] * 256 + data[4]) / 65535.0 return celsius, humidity def get_power_stats(self): try: voltage = self.powergauge_module.cell_voltage power = self.powergauge_module.cell_percent except Exception as e: voltage = None power = None return power, voltage
class GroveTemperatureHumiditySensorSHT3x(object): def __init__(self, address=0x45, bus=None): self.address = address # I2C bus self.bus = Bus(bus) def CRC(self, data): crc = 0xff for s in data: crc ^= s for i in range(8): if crc & 0x80: crc <<= 1 crc ^= 0x131 else: crc <<= 1 return crc def read(self): # High repeatability, clock stretching disabled self.bus.write_i2c_block_data(self.address, 0x24, [0x00]) # Measurement duration < 16 ms time.sleep(0.016) # Read 6 bytes back: # Temp MSB, Temp LSB, Temp CRC, # Humididty MSB, Humidity LSB, Humidity CRC data = self.bus.read_i2c_block_data(0x45, 0x00, 6) temperature = data[0] * 256 + data[1] celsius = -45 + (175 * temperature / 65535.0) humidity = 100 * (data[3] * 256 + data[4]) / 65535.0 if data[2] != self.CRC(data[:2]): raise RuntimeError("Temperature CRC mismatch") if data[5] != self.CRC(data[3:5]): raise RuntimeError("Humidity CRC mismatch") return celsius, humidity
class GroveAlphanumDisplay(object): def __init__(self, address=0x71, brightness=BRIGHT_DEFAULT, display_type=FOUR_TUBES): """ Constructor Args: address: I2C address, default is 0x71 brightness: Startup brightness, value between 0 and 15 display_type: Display type, can be one of 0: FOUR_TUBES and 1: TWO_TUBES """ self.address = address self.display_type = display_type self.font = display_font4 if display_type == FOUR_TUBES else display_font2 self.first_dot = False self.second_dot = False self.bus = Bus() self.data = [0] * 4 if self.display_type == FOUR_TUBES else 2 self.bus.write_i2c_block_data(self.address, REG_INIT, []) self.bus.write_i2c_block_data(self.address, DISP_ON, []) self.set_brightness(brightness) def clear(self): """ Clear display """ self.data = [0] * 4 if self.display_type == FOUR_TUBES else 2 self.first_dot = False self.second_dot = False self._show() def show(self, data): """ Show a string on the display Args: data: String to show. If it is longer than the display size (2 or 4), the string is trimmed to display length. """ if type(data) is str: self.data = [0] * 4 if self.display_type == FOUR_TUBES else 2 length = min(len(data), len(self.data)) for i in range(length): self.data[i] = self.font.get(data[i], 0) else: raise ValueError('Not support {}'.format(type(data))) self._show() def _show(self): """ Internal function to show the display data. First, create the I2C data to write to the display controller and then send it. """ wire_bytes = [0, 0] byte_10 = 0 byte_11 = 0 if self.display_type == FOUR_TUBES: for d in self.data: wire_bytes += [d & 0xFF, (d >> 8) & 0xFF] for i, d in enumerate(self.data): if i == 0: byte_10 |= (1 if (d & 0x02) else 0) << 4 byte_10 |= (1 if (d & 0x04) else 0) << 3 elif i == 1: byte_10 |= (1 if (d & 0x02) else 0) << 6 byte_11 |= (1 if (d & 0x04) else 0) << 6 elif i == 2: byte_10 |= (1 if (d & 0x02) else 0) << 5 byte_11 |= (1 if (d & 0x04) else 0) << 1 else: byte_11 |= (1 if (d & 0x02) else 0) << 2 byte_11 |= (1 if (d & 0x04) else 0) << 0 if self.first_dot: byte_10 |= self.font['first_dot'] & 0xFF byte_11 |= (self.font['first_dot'] >> 8) & 0xFF if self.second_dot: byte_10 |= self.font['second_dot'] & 0xFF byte_11 |= (self.font['second_dot'] >> 8) & 0xFF else: for i in [1, 0]: value = self.data[i] if i == 1 and self.first_dot: value |= self.font['dot'] if i == 0 and self.second_dot: value |= self.font['dot'] wire_bytes += [(value >> 8) & 0xFF, value & 0xFF] wire_bytes += [0] * 4 wire_bytes += [byte_10, byte_11] self.bus.write_i2c_block_data(self.address, 0, wire_bytes) def set_brightness(self, brightness): """ Sets the LED brightness. Args: brightness: Brightness as integer, value between 0 and 15 """ if brightness > BRIGHT_HIGHEST or brightness < 0: brightness = BRIGHT_HIGHEST self.bus.write_byte(self.address, REG_BRIGHT | brightness) def set_blink_type(self, blink_type): """ Configures the blinking of the display, can be one of: - 0: No blinking - 1: Blink with 2 Hz - 2: Blink with 1 Hz Args: blink_type: Blinking type """ if 0 <= blink_type <= 2: self.bus.write_byte(self.address, 0x81 | (blink_type << 1)) def set_dots(self, first, second): """ Sets the dots in the display. Args: first: If set, the first/upper dot is on second: If set, the second/lower dot is on """ self.first_dot = first self.second_dot = second self._show()
class SGP30: def __init__(self): self.bus = Bus() # SGB30 i2c default address is 0x58 self.address = 0x58 self.crc_status = [0, 0] self.CO2eq = 0 self.TVOC = 0 self.CO2eq_raw = 0 self.TVOC_raw = 0 self.CO2eq_baseline = 0 self.TVOC_baseline = 0 ######################################### # Command functions # ######################################### # Init air quality command # A new “Init_air_quality” command has to be sent after every power-up or soft reset. def init_air_quality(self): command = ([0x20, 0x03], 0, 10) try: self.read_write(command) except Exception: # On fail return 0 print("sgp30 Init Fail!") return 0 else: print("sgp30 Init Ok!") # Command pass return 1 return 1 # Measure compensated Co2eq and TVOC values # Has to be sent regular intervals 1s to ensure proper operation of dynamic baseline correction algorithm def measure_air_quality(self): command = ([0x20, 0x08], 6, 12) data = self.read_write(command) if self.crc_status[0] == 0: print("Measurement CRC check failed", self.crc_status) self.CO2eq = 0 self.TVOC = 0 return 0 else: self.CO2eq = bytes_to_int(data[0:2]) self.TVOC = bytes_to_int(data[3:5]) return 1 # Get compensation baseline values # def get_baseline(self): command = ([0x20, 0x15], 6, 10) try: data = self.read_write(command) except Exception: # On fail return 0 print("get_baseline() => read_write() failed.") return 0 if self.crc_status[0] == 0: print("Basevalue read CRC check failed", self.crc_status) return 0 else: self.CO2eq_baseline = bytes_to_int(data[0:2]) self.TVOC_baseline = bytes_to_int(data[3:5]) return 1 # Set compensation baseline values # Sets also variables sgp30(Instance).CO2eq_baseline and sgp30(Instance).TVOC_baseline def set_baseline(self, message): command = ([0x20, 0x1e], 0, 10) formatted_data = [] # generate correct message format [HByte, LByte, CRC, HByte, LByte, CRC, ...] for number in message: tmp_bytes = int_to_bytes(number) crc = calc_crc8(tmp_bytes) formatted_data.extend(tmp_bytes) formatted_data.append(crc) # Extend command data with with message command[0].extend(formatted_data) try: self.read_write(command) except Exception: # On fail return 0 print("set_baseline() => read_write() failed.") return 0 else: self.TVOC_baseline = message[0] self.CO2eq_baseline = message[1] print("Compensation baseline values writen successfully.") return 1 # Set humidity compensation value # def set_humidity(self, message): command = ([0x20, 0x61], 0, 10) formatted_data = [] # generate correct message format [HByte, LByte, CRC, HByte, LByte, CRC, ...] for number in message: tmp_bytes = int_to_bytes(number) crc = calc_crc8(tmp_bytes) formatted_data.extend(tmp_bytes) formatted_data.append(crc) # Extend command data with with message command[0].extend(formatted_data) try: self.read_write(command) except Exception: # On fail return 0 print("set_humidity() => read_write() failed.") return 0 else: print("Humidity compensation value writen successfully.") return 1 # Measure test # The command “Measure_test” which is included for integration and production line testing runs an on-chip # self-test. In case of a successful self-test the sensor returns the fixed data pattern 0xD400 (with correct CRC) def measure_test(self): command = ([0x20, 0x32], 3, 220) data = self.read_write(command) if self.crc_status[0] == 0: print("Measurement CRC check failed", self.crc_status) return 0 else: print("On-chip self-test succesfull!") return bytes_to_int(data[0:2]) def get_feature_set_version(self): command = ([0x20, 0x2f], 3, 2) data = self.read_write(command) print("Product type: ", '{0:08b}'.format(data[0])[0:4]) print("Product version: ", '{0:08b}'.format(data[1]) + ", " + str(data[1])) def measure_raw_signals(self): command = ([0x20, 0x50], 6, 25) data = self.read_write(command) if self.crc_status[0] == 0: print("Measurement CRC check failed", self.crc_status) self.CO2eq_raw = 0 self.TVOC_raw = 0 return 0 else: self.CO2eq_raw = bytes_to_int(data[0:2]) self.TVOC_raw = bytes_to_int(data[3:5]) return 1 # Soft reset command # A sensor reset can be generated using the “General Call” mode according to I2C-bus specification. # It is important to understand that a reset generated in this way is not device specific. # All devices on the same I2C bus that support the General Call mode will perform a reset. def soft_reset(self): command = ([0x00, 0x06], 0, 10) self.read_write(command) # Get serial ID def get_serial_id(self): command = ([0x36, 0x82], 9, 10) data = self.read_write(command) if self.crc_status[0] == 0: print("Measurement CRC check failed", self.crc_status) return 0 else: print("Get serial succesfull!") print("Serial part 1: ", '{0:016b}'.format(bytes_to_int(data[0:2]))) print("Serial part 2: ", '{0:016b}'.format(bytes_to_int(data[3:5]))) print("Serial part 3: ", '{0:016b}'.format(bytes_to_int(data[7:9]))) return 1 ######################################### # read and write data to the sgp30 # ######################################### def read_write(self, command): if command[1] <= 0: # Write to I2C-bus # write_i2c_block_data(address, offset, [data_bytes]) # Note that second offset byte is [data_bytes][0] self.bus.write_i2c_block_data(self.address, command[0][0], command[0][1:]) sleep(command[2]/1000) return 1 else: # Read (Write and read) from I2C-Bus # write_i2c_block_data(address, offset, [data_bytes]) # Note that second offset byte is [data_bytes][0] # read_i2c_block_data(address, offset, number_of_data_bytes) self.bus.write_i2c_block_data(self.address, command[0][0], [command[0][1]]) sleep(command[2]/1000) data = self.bus.read_i2c_block_data(self.address, 0, command[1]) self.crc_status = validate_crc8(data) return data
class DHT(object): DHT_TYPE = {'DHT11': '11', 'DHT22': '22', 'DHT10': '10'} DEFAULT_ADDR = 0x38 RESET_REG_ADDR = 0xba MAX_CNT = 320 PULSES_CNT = 41 def __init__(self, dht_type, pin=12, bus_num=1): if dht_type != self.DHT_TYPE['DHT11'] and dht_type != self.DHT_TYPE[ 'DHT22'] and dht_type != self.DHT_TYPE['DHT10']: print('ERROR: Please use 11|22|10 as dht type.') exit(1) self.dht_type = dht_type if dht_type == self.DHT_TYPE['DHT10']: self.bus = Bus(bus_num) self.addr = self.DEFAULT_ADDR self._dht10_init() else: self.pin = GPIO(pin, GPIO.OUT) self._last_temp = 0.0 self._last_humi = 0.0 @property def dht_type(self): return self._dht_type @dht_type.setter def dht_type(self, type): self._dht_type = type ######################## dht10 ############################ def _dht10_start_mess(self): reg_set = [0x33, 0x00] self.bus.write_i2c_block_data(self.addr, 0xac, reg_set) def _dht10_reset(self): self.bus.write_byte(self.addr, self.RESET_REG_ADDR) def _dht10_set_system_cfg(self): reg_set = [0x08, 0x00] self.bus.write_i2c_block_data(self.addr, 0xe1, reg_set) def _dht10_read_status(self): return self.bus.read_byte_data(self.addr, 0) def _dht10_init(self): time.sleep(.5) self._dht10_reset() # delay is needed after reset time.sleep(.3) self._dht10_set_system_cfg() status = self._dht10_read_status() # we must check the calibrate flag, bit[3] : 1 for calibrated ok,0 for Not calibrated. while status & 0x08 != 0x08: print("try calibrated again!n\n") self._dht10_reset() time.sleep(.5) self.bus.dth10_set_system_cfg() status = self._dht10_read_status() time.sleep(.5) ######################################################### def _read(self): if self.dht_type == self.DHT_TYPE['DHT10']: t = 0 h = 0 self._dht10_start_mess() time.sleep(.075) # we must check the device busy flag, bit[7] : 1 for busy ,0 for idle. while (self._dht10_read_status() & 0x80) != 0: time.sleep(.5) print("wait for device not busy") from smbus2 import SMBus, i2c_msg, SMBusWrapper with SMBusWrapper(1) as bus: msg = i2c_msg.read(self.addr, 6) data = bus.i2c_rdwr(msg) data = list(msg) t = (t | data[1]) << 8 t = (t | data[2]) << 8 t = (t | data[3]) >> 4 h = (h | data[3]) << 8 h = (h | data[4]) << 8 h = (h | data[5]) & 0xfffff t = t * 100.0 / 1024 / 1024 h = h * 200.0 / 1024 / 1024 - 50 return t, h # Send Falling signal to trigger sensor output data # Wait for 20ms to collect 42 bytes data else: self.pin.dir(GPIO.OUT) self.pin.write(1) time.sleep(.2) self.pin.write(0) time.sleep(.018) self.pin.dir(GPIO.IN) # a short delay needed for i in range(10): pass # pullup by host 20-40 us count = 0 while self.pin.read(): count += 1 if count > self.MAX_CNT: # print("pullup by host 20-40us failed") return None, "pullup by host 20-40us failed" pulse_cnt = [0] * (2 * self.PULSES_CNT) fix_crc = False for i in range(0, self.PULSES_CNT * 2, 2): while not self.pin.read(): pulse_cnt[i] += 1 if pulse_cnt[i] > self.MAX_CNT: # print("pulldown by DHT timeout %d" % i) return None, "pulldown by DHT timeout %d" % i while self.pin.read(): pulse_cnt[i + 1] += 1 if pulse_cnt[i + 1] > self.MAX_CNT: # print("pullup by DHT timeout %d" % (i + 1)) if i == (self.PULSES_CNT - 1) * 2: # fix_crc = True # break pass return None, "pullup by DHT timeout %d" % i total_cnt = 0 for i in range(2, 2 * self.PULSES_CNT, 2): total_cnt += pulse_cnt[i] # Low level ( 50 us) average counter average_cnt = total_cnt / (self.PULSES_CNT - 1) # print("low level average loop = %d" % average_cnt) data = '' for i in range(3, 2 * self.PULSES_CNT, 2): if pulse_cnt[i] > average_cnt: data += '1' else: data += '0' data0 = int(data[0:8], 2) data1 = int(data[8:16], 2) data2 = int(data[16:24], 2) data3 = int(data[24:32], 2) data4 = int(data[32:40], 2) if fix_crc and data4 != ((data0 + data1 + data2 + data3) & 0xFF): data4 = data4 ^ 0x01 data = data[0:self.PULSES_CNT - 2] + ('1' if data4 & 0x01 else '0') if data4 == ((data0 + data1 + data2 + data3) & 0xFF): if self._dht_type == self.DHT_TYPE['DHT11']: humi = int(data0) temp = int(data2) elif self._dht_type == self.DHT_TYPE['DHT22']: humi = float(int(data[0:16], 2) * 0.1) temp = float( int(data[17:32], 2) * 0.2 * (0.5 - int(data[16], 2))) else: # print("checksum error!") return None, "checksum error!" return humi, temp def read(self, retries=15): for i in range(retries): humi, temp = self._read() if not humi is None: break if humi is None: return self._last_humi, self._last_temp self._last_humi, self._last_temp = humi, temp return humi, temp
class Grove12KeyCapTouchMpr121(): def __init__(self,bus_num = 1,addr = TOUCH_SENSOR_DEFAULT_ADDR): self.bus = Bus(bus_num) self.addr = addr self.threshold = 0 self.touch_flag = [0]*CHANNEL_NUM def sensor_init(self): self._set_mode(STOP_MODE) data = [0x23,0x10] self._set_global_param(data) self._set_debounce(0x22) self._set_mode(NORMAL_MODE) def set_threshold(self,threshold): self.threshold = threshold def wait_for_ready(self): time.sleep(.2) def _set_mode(self,mode): self.bus.write_byte_data(self.addr,MODE_CONFIG_REG_ADDR,mode) def _set_global_param(self,data): self.bus.write_i2c_block_data(self.addr,GLOBAL_PARAM_REG_ADDR_L,data) def _set_debounce(self,data): self.bus.write_byte_data(self.addr,SET_DEBOUNCE_REG_ADDR,data) def _check_status_register(self): data_status = self.bus.read_i2c_block_data(self.addr,TOUCH_STATUS_REG_ADDR_L,2) return data_status def get_filtered_touch_data(self,sensor_status): result_value = [] for i in range(CHANNEL_NUM): time.sleep(.01) if(sensor_status & (1<<i)): channel_data = self.bus.read_i2c_block_data(self.addr,FILTERED_DATA_REG_START_ADDR_L+2*i,2) result_value.append(channel_data[0] | channel_data[1]<<8 ) else: result_value.append(0) return result_value def listen_sensor_status(self): data = self._check_status_register() touch_status = data[0] | (data[1]<<8) touch_result_value = self.get_filtered_touch_data(touch_status) for i in range(CHANNEL_NUM): if(touch_result_value[i] < self.threshold ): touch_result_value[i] = 0 return touch_result_value def parse_and_print_result(self,result): for i in range(CHANNEL_NUM): if(result[i] != 0): if(0 == self.touch_flag[i]): self.touch_flag[i] = 1 print("Channel %d is pressed,value is %d" %(i,result[i])) else: if(1 == self.touch_flag[i]): self.touch_flag[i] = 0 print("Channel %d is released,value is %d" %(i,result[i]))
class I2CStepperMotor(StepperMotor): __REG_GET_PID = 0x00 __REG_GET_VID = 0x01 __REG_GET_VER = 0x02 __REG_STP_EN = 0x1A __REG_STP_DIS = 0x1B __REG_STP_RUN = 0x1C __REG_STP_INTERVAL = 0x1D __REG_SEQ_LEN = 0x20 __REG_SEQ_XET = 0x21 __REG_SET_SPEED = 0x82 __REG_SET_FREQ = 0x84 __REG_SET_A = 0xA1 __REG_SET_B = 0xA5 __REG_SET_DIR = 0xAA def __init__(self, arguments, address=0x0F): super(I2CStepperMotor, self).__init__(arguments) self._addr = address self._bus = Bus() self._ang_left = 0 self._load_seq(arguments["sequences"]) def __del__(self): self.set_speed(0, 0) pass #Maps speed from 0-100 to 0-255 def _map_vals(self, value, leftMin, leftMax, rightMin, rightMax): #http://stackoverflow.com/questions/1969240/mapping-a-range-of-values-to-another # Figure out how 'wide' each range is leftSpan = leftMax - leftMin rightSpan = rightMax - rightMin # Convert the left range into a 0-1 range (float) valueScaled = float(value - leftMin) / float(leftSpan) # Convert the 0-1 range into a value in the right range. return int(rightMin + (valueScaled * rightSpan)) #Set motor speed def set_speed(self, speed1=0, speed2=0): s1 = self._map_vals(speed1, 0, 100, 0, 255) s2 = self._map_vals(speed2, 0, 100, 0, 255) self._bus.write_i2c_block_data(self._addr, self.__REG_SET_SPEED, [s1, s2]) time.sleep(.02) #Set motor direction def set_dir(self, clock_wise1=True, clock_wise2=True): dir1 = 0b10 if clock_wise1 else 0b01 dir2 = 0b10 if clock_wise2 else 0b01 dir = (dir2 << 2) | dir1 self._bus.write_i2c_block_data(self._addr, self.__REG_SET_DIR, [dir, 0]) time.sleep(.02) def _load_seq(self, seq): length = len(seq) self._bus.write_word_data(self._addr, self.__REG_SEQ_LEN, length) for i in range(len(seq)): self._bus.write_word_data(self._addr, self.__REG_SEQ_XET, seq[i]) def _enable(self, en): cmd = self.__REG_STP_EN if en else self.__REG_STP_DIS if en: self.set_speed(self.DC_SPEED_MAX, self.DC_SPEED_MAX) else: self.set_speed(0, 0) self._bus.write_i2c_block_data(self._addr, cmd, [self._dir, 0]) time.sleep(0.001) def _speed(self, rpm): self._dir = self._DIR_CLKWISE if rpm >= 0 else self._DIR_ANTI_CLKWISE # absolute angle per second aps = abs(rpm) * 360.0 / 60.0 # steps per second, include reductor ratio. sps = self._angle2steps(aps) period = int(1000000 / sps) # us period = period // 10 # STP_INTERVAL, 10 us # print("period = %d us" % (period * 10)) self._bus.write_word_data(self._addr, self.__REG_STP_INTERVAL, period) time.sleep(0.001) def _rotate(self, angle=None): if not angle is None: angle = abs(angle) self._ang_left = angle steps = self._angle2steps(angle) # print("steps set = {}".format(steps)) self._bus.write_word_data(self._addr, self.__REG_STP_RUN, steps) time.sleep(0.001) return angle while True: # reading interface unstable when working try: steps = self._bus.read_word_data(self._addr, self.__REG_STP_RUN) # print("steps left = {}".format(steps)) ang_left = self._steps2angle(steps) if ang_left > self._ang_left: time.sleep(0.01) continue self._ang_left = ang_left return ang_left except IOError: continue
class bme280: """ Grove bme280 sensor control library. Objects: - set_mode(mode, t_sb) - set_oversampling(osrs_h, osrs_t, osrs_p) - set_filter(filter_coefficient) - set_spi(spi3w_en) - write_reset() - read_id() - read_status() - read_compensated_signals() - read_raw_signals() - set_pressure_calibration(level, pressure) - get_altitude(pressure) """ # Constant Definitions # Modes MODE_SLEEP = 0b00 MODE_FORCE = 0b01 MODE_NORMAL = 0b11 # Normal mode standby values t_sb_0_5 = 0b000 t_sb_62_5 = 0b001 t_sb_125 = 0b010 t_sb_250 = 0b011 t_sb_500 = 0b100 t_sb_1000 = 0b101 t_sb_10 = 0b110 t_sb_20 = 0b111 # IIR filter coefficient filter_0 = 0b000 filter_2 = 0b001 filter_4 = 0b010 filter_8 = 0b011 filter_16 = 0b100 # SPI control SPI_ON = 0b01 SPI_OFF = 0b00 # Oversampling modes OVRS_x0 = 0b000 OVRS_x1 = 0b001 OVRS_x2 = 0b010 OVRS_x4 = 0b011 OVRS_x8 = 0b100 OVRS_x16 = 0b101 def __init__(self): # Rev 2 Pi, Pi 2 & Pi 3 uses bus 1, Rev 1 Pi uses bus 0 # bme280 default I2C Address is 0x76 self.bus = Bus() self.address = 0x76 self.mode = self.MODE_SLEEP self.t_sb = self.t_sb_1000 self.last_meas = 0 # Calibration data # Calibration data registers are 0x88-0xA1(25 bytes) and 0xE1-0xE7(7 bytes) total 32 bytes self.calib = [0x00] * 32 # Init raw data array and variables self.raw_data = [0x00] * 8 self.raw_temperature = 0x00000 self.raw_pressure = 0x00000 self.raw_humidity = 0x00000 # Init parameters self.osrs_h = self.OVRS_x0 self.osrs_t = self.OVRS_x0 self.osrs_p = self.OVRS_x0 # IIR filter and SPI interface are off by default self.filter = self.filter_0 self.spi3w_en = self.SPI_OFF # Status word. Only has two significant bits bit0 = im_update and bit3 = measuring self.status = 0x00 self.im_update = False self.measuring = False # Compensation values # Temperature trimming values self.dig_T1 = 0x0000 self.dig_T2 = 0x0000 self.dig_T3 = 0x0000 # Pressure trimming params self.dig_P1 = 0x0000 self.dig_P2 = 0x0000 self.dig_P3 = 0x0000 self.dig_P4 = 0x0000 self.dig_P5 = 0x0000 self.dig_P6 = 0x0000 self.dig_P7 = 0x0000 self.dig_P8 = 0x0000 self.dig_P9 = 0x0000 # Humidity trimming params self.dig_H1 = 0x00 self.dig_H2 = 0x0000 self.dig_H3 = 0x00 self.dig_H4 = 0x0000 self.dig_H5 = 0x0000 self.dig_H6 = 0x00 # Get the trimming values self.__read_calib() # Variables for compensated measurements self.temperature = 0x00000 self.pressure = 0x00000 self.humidity = 0x00000 self.calibrated_temperature = 0x00000 self.calibrated_pressure = 0x00000 self.calibrated_humidity = 0x00000 # Variables for measurement calibration self.calibration_temperature = 0 self.calibration_pressure = 0 self.calibration_humidity = 0 ######################################### # set bme280 operating mode # ######################################### def set_mode(self, mode=MODE_SLEEP, t_sb=t_sb_1000): # Writes ctrl_meas register with current temperature and pressure oversampling settings # Only changes the mode # If normal mode selected also sets the standby time in config register # Set class variables self.mode = mode self.t_sb = t_sb # If no measurements are enabled there is no point going into measurement if self.osrs_t + self.osrs_p + self.osrs_h == 0: print( "No measurement enabled!\nSee set_oversampling()-function to enable measurement." ) return 0 try: # If normal mode set also t_sb(standby time) if self.mode == self.MODE_NORMAL: # Write normal mode standby time t_sb to config register self.__config(t_sb, self.filter, self.spi3w_en) # Write mode to ctr_meas register self.__ctrl_meas(self.osrs_t, self.osrs_p, self.mode) # Otherwise just change the mode in ctrl_meas register else: self.__ctrl_meas(self.osrs_t, self.osrs_p, self.mode) self.last_meas = clock_gettime(CLOCK_REALTIME) # Everything went well return 1 return 1 except Exception as e: # e = sys.exc_info()[0] print("<p>Error: %s</p>" % e) return 0 ######################################################################### # Set oversampling/enable measurement. OVRS_x0 disables the measurement # ######################################################################### def set_oversampling(self, osrs_h=OVRS_x0, osrs_t=OVRS_x0, osrs_p=OVRS_x0): # Set oversampling variables self.osrs_h = osrs_h self.osrs_t = osrs_t self.osrs_p = osrs_p try: # Set humidity oversampling self.__ctrl_hum(self.osrs_h) # Set temperature and pressure oversampling self.__ctrl_meas(self.osrs_t, self.osrs_p, self.mode) except Exception as e: # e = sys.exc_info()[0] print("<p>Error: %s</p>" % e) return 0 # Everything went well return 1 return 1 ######################################### # Set internal IIR filter # ######################################### def set_filter(self, filter_coefficient=filter_0): self.filter = filter_coefficient try: # Write config register with new filter setting self.__config(self.t_sb, self.filter, self.spi3w_en) return 1 except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # Set internal SPI interface # ######################################### def set_spi(self, spi3w_en=SPI_OFF): self.spi3w_en = spi3w_en try: # Write config register with new spi setting self.__config(self.t_sb, self.filter, self.spi3w_en) return 1 except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # Reset command # ######################################### def write_reset(self): register = 0xE0 data = 0xB6 # Reset command to register, other values than 0xB6 has no effect r_len = 0 delay = 10 command = ([register, data], r_len, delay) try: self.read_write(command) return 1 except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # read ID register # ######################################### def read_id(self): register = 0xD0 data = 0x00 r_len = 1 delay = 10 command = ([register, data], r_len, delay) try: return hex(self.read_write(command)[0]) except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # read STATUS register # ######################################### def read_status(self): register = 0xF3 data = 0x00 r_len = 1 delay = 10 command = ([register, data], r_len, delay) try: self.status = self.read_write(command)[0] self.measuring = (self.status >> 3) & 0b1 self.im_update = self.status & 0b1 return [self.status, self.measuring, self.im_update] except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # read calibration registers # ######################################### def __read_calib(self): # Calibration data registers are 0x88-0xA1(25 bytes) and 0xE1-0xE7(7 bytes) total 32 bytes # command format ([Register, Data Bytes], Number of bytes to read, Additional sleep(ms)) # If Number of bytes to read > 0 then read_write function reads from I2C Bus # Otherwise Write operation is performed. register1 = 0x88 register2 = 0xE1 data = 0x00 r_len1 = 26 r_len2 = 7 delay = 10 command1 = ([register1, data], r_len1, delay) command2 = ([register2, data], r_len2, delay) try: self.calib[0:26] = self.read_write(command1) self.calib[26:32] = self.read_write(command2) except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 # Assign fetched data to trim parameters # Temperature trimming params # unsigned are ok, signed must be calculated with twos complement bytes_short = 16 bytes_char = 8 self.dig_T1 = (self.calib[1] << 8) + (self.calib[0] & 0xffff) self.dig_T2 = self.__twos_complement( ((self.calib[3] << 8) + self.calib[2]), bytes_short) self.dig_T3 = self.__twos_complement( (self.calib[5] << 8) + self.calib[4], bytes_short) # Pressure trimming params self.dig_P1 = ((self.calib[7] << 8) + self.calib[6]) & 0xffff self.dig_P2 = self.__twos_complement( (self.calib[9] << 8) + self.calib[8], bytes_short) self.dig_P3 = self.__twos_complement( (self.calib[11] << 8) + self.calib[10], bytes_short) self.dig_P4 = self.__twos_complement( (self.calib[13] << 8) + self.calib[12], bytes_short) self.dig_P5 = self.__twos_complement( (self.calib[15] << 8) + self.calib[14], bytes_short) self.dig_P6 = self.__twos_complement( (self.calib[17] << 8) + self.calib[16], bytes_short) self.dig_P7 = self.__twos_complement( (self.calib[19] << 8) + self.calib[18], bytes_short) self.dig_P8 = self.__twos_complement( (self.calib[21] << 8) + self.calib[20], bytes_short) self.dig_P9 = self.__twos_complement( (self.calib[23] << 8) + self.calib[22], bytes_short) # Humidity trimming params self.dig_H1 = self.calib[25] & 0xff self.dig_H2 = self.__twos_complement( (self.calib[27] << 8) + self.calib[26], bytes_short) self.dig_H3 = self.calib[28] & 0xff self.dig_H4 = self.__twos_complement( (self.calib[29] << 4) + (self.calib[30] & 0x0f), bytes_short) self.dig_H5 = self.__twos_complement( (self.calib[31] << 4) + ((self.calib[30] & 0xf0) >> 4), bytes_short) self.dig_H6 = self.__twos_complement(self.calib[32], bytes_char) # Everything went well return 1 return 1 ######################################### # read raw signals registers # ######################################### def read_raw_signals(self): # RAW Signals memory area is 0xF7-0xFE so there is 8 bytes # command format ([Register, Data Bytes], Number of bytes to read, Additional sleep(ms)) # If Number of bytes to read > 0 then read_write function reads from I2C Bus # Otherwise Write operation is performed. register = 0xF7 data = 0x00 r_len = 8 delay = 10 command = ([register, data], r_len, delay) try: self.raw_data = self.read_write(command) self.raw_pressure = (( (self.raw_data[0] << 8) + self.raw_data[1]) << 4) + ( (self.raw_data[2] >> 4) & 0x0f) self.raw_temperature = ((( (self.raw_data[3] << 8) + self.raw_data[4]) << 4) + ((self.raw_data[5] >> 4) & 0x0f)) self.raw_humidity = ((self.raw_data[6] << 8) + self.raw_data[7]) except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 # Everything went well return 1 return 1 ######################################### # read compensated signals # ######################################### def read_compensated_signals(self): # Assuming that raw signals are already read # Compensation is performed like in datasheet appendix 8 # 8.1 Compensation formulas in double precision floating point try: # Get Temperature t_fine value t_fine = self.__comp_temperature() self.temperature = t_fine / 5120.0 # Output value of “51.23” equals 51.23 DegC self.calibrated_temperature = ( self.temperature + (0 if self.calibration_temperature is 0 else self.calibration_temperature)) # Get pressure self.pressure = self.__comp_pressure(t_fine) / 100.0 self.calibrated_pressure = (self.pressure + (0 if self.calibration_pressure is 0 else self.calibration_pressure)) # Get Humidity self.humidity = self.__comp_humidity(t_fine) self.calibrated_humidity = (self.humidity + (0 if self.calibration_humidity is 0 else self.calibration_humidity)) return 1 except Exception as e: # print("Error in set_filter()") print("<p>Error: %s</p>" % e) return 0 ######################################### # Temperature compensation formulas # # returns t_fine, because it is used in # # other compensation formulas # ######################################### def __comp_temperature(self): var1 = ((self.raw_temperature / 16384.0) - (self.dig_T1 / 1024.0)) * self.dig_T2 var2 = ((((self.raw_temperature / 131072.0) - (self.dig_T1 / 8192.0)) * ((self.raw_temperature / 131072.0) - (self.dig_T1 / 8192.0))) * self.dig_T3) # t_fine = var1 + var2 return var1 + var2 ############################################################# # Pressure compensation formulas # # Returns pressure in Pa as double. # # Output value of “96386.2” equals 96386.2 Pa = 963.862 hPa # ############################################################# def __comp_pressure(self, t_fine): var1 = (t_fine / 2.0) - 64000.0 var2 = var1 * var1 * self.dig_P6 / 32768.0 var2 = var2 + var1 * self.dig_P5 * 2.0 var2 = (var2 / 4.0) + (self.dig_P4 * 65536.0) var1 = (self.dig_P3 * var1 * var1 / 524288.0 + self.dig_P2 * var1) / 524288.0 var1 = (1.0 + var1 / 32768.0) * self.dig_P1 if var1 == 0.0: return 0 # avoid exception caused by division by zero p = 1048576.0 - self.raw_pressure p = (p - (var2 / 4096.0)) * 6250.0 / var1 var1 = self.dig_P9 * p * p / 2147483648.0 var2 = p * self.dig_P8 / 32768.0 p = p + (var1 + var2 + self.dig_P7) / 16.0 return p ################################################## # Humidity compensation formulas # # Returns humidity in %rH as as double. # # Output value of “46.332” represents 46.332 %rH # ################################################## def __comp_humidity(self, t_fine): var_h = t_fine - 76800.0 var_h = ((self.raw_humidity - (self.dig_H4 * 64.0 + (self.dig_H5 / 16384.0 * var_h))) * (self.dig_H2 / 65536.0 * (1.0 + self.dig_H6 / 67108864.0 * var_h * (1.0 + self.dig_H3 / 67108864.0 * var_h)))) var_h = var_h * (1.0 - self.dig_H1 * var_h / 524288.0) if var_h > 100.0: var_h = 100.0 elif var_h < 0.0: var_h = 0.0 return var_h ######################################### # write ctrl_hum register # ######################################### def __ctrl_hum(self, osrs_h=OVRS_x0): register = 0xF2 r_len = 0 delay = 10 # Make byte to send # data = ((0x00 << 3) + osrs_h) data = osrs_h command = ([register, data], r_len, delay) self.read_write(command) ######################################### # write ctrl_meas register # ######################################### def __ctrl_meas(self, osrs_t=OVRS_x0, osrs_p=OVRS_x0, mode=MODE_SLEEP): register = 0xF4 r_len = 0 delay = 10 # Make byte to send data = ((((osrs_t << 3) + osrs_p) << 2) + mode) command = ([register, data], r_len, delay) self.read_write(command) ######################################### # write config register # ######################################### def __config(self, t_sb, iir_filter, spi3w_en): register = 0xF5 r_len = 0 delay = 10 # Make byte to send data = ((((t_sb << 3) + iir_filter) << 2) + spi3w_en) command = ([register, data], r_len, delay) self.read_write(command) ############################################################## # set_pressure_calibration # # level = known level from sea # # pressure = current local pressure normalized to sea level # ############################################################## def set_pressure_calibration(self, level, pressure): self.calibration_pressure = (pressure - level / 8) - self.pressure ######################################### # get current altitude # # pressure = current sea level pressure # ######################################### def get_altitude(self, pressure): return (pressure - self.calibrated_pressure) * 8 ########################################### # read and write data to the bme280/(I2C) # ########################################### def read_write(self, command): if command[1] <= 0: # Write to I2C-bus # write_i2c_block_data(address, offset, [data_bytes]) self.bus.write_i2c_block_data(self.address, command[0][0], command[0][1:]) sleep(command[2] / 1000) return 1 else: # Read from I2C-Bus # read_i2c_block_data(address, register, number_of_data_bytes) return self.bus.read_i2c_block_data(self.address, command[0][0], command[1]) ######################################### # Twos complement calculation # ######################################### @staticmethod def __twos_complement(input_value, num_bits): """Calculates a two's complement integer from the given input value's bits.""" mask = 2**(num_bits - 1) return -(input_value & mask) + (input_value & (mask - 1))
class Tsl2561: i2c = None def __init__(self, bus=I2C_SMBUS, address=I2C_ADDRESS, debug=1, pause=0.8): # assert(bus is not None) # assert(address > 0b000111 and address < 0b1111000) self.address = address self.bus = Bus(bus) self.pause = pause self.debug = debug self.gain = 0 self._bus = bus self._addr = address ambient = None IR = None self._ambient = 0 self._IR = 0 self._LUX = None self._control(_POWER_UP) self._partno_revision() def _reverseByteOrder(self, data): """Reverses the byte order of an int (16-bit) or long (32-bit) value""" # Courtesy Vishal Sapre byteCount = len(hex(data)[2:].replace('L','')[::2]) val = 0 for i in range(byteCount): val = (val << 8) | (data & 0xff) data >>= 8 return val def _read_byte(self, address): command = _CMD | address self.bus.read_byte_data(self.address, command) def _read_word(self, address,little_endian=True): try: command = _CMD | address result = self.bus.read_word_data(self.address, command) if not little_endian: result = ((result << 8) & 0xFF00) + (result >> 8) if (self.debug): print ("I2C: Device 0x{} returned 0x{} from reg 0x{}".format(self.address, result & 0xFFFF, reg)) return result except IOError, err: return self.errMsg() def _write_byte(self, address, data): command = _CMD | address self.bus.write_byte_data(self.address, command, data) def _write_word(self, address, data): command = _CMD | _AUTO | address data = [(data >> 8) & 0xFF, data & 0xFF] self.bus.write_i2c_block_data(self.address, command, data) def setGain(self, gain = 1): """ Set the gain """ if (gain != self.gain): if (gain==1): cmd = _CMD | _REG_TIMING value = 0x02 self._write_byte(cmd, value) if (self.debug): print ("Setting low gain") else: cmd = _CMD | _REG_TIMING value = 0x12 self._write_byte(cmd, value) if (self.debug): print ("Setting high gain") self.gain = gain # Safe gain for calculation print('setGain...gian=',gain) time.sleep(self.pause) # Pause for integration (self.pause must be bigger than integration time) def readWord(self, reg): """ Reads a word from the TSL2561 I2C device """ try: wordval = self._read_word(reg) print ('wordval=',wordval) newval = self._reverseByteOrder(wordval) print ('newval=',newval) if (self.debug): print("I2C: Device 0x{}: returned 0x{} from reg 0x{}".format(self._addr, wordval & 0xFFFF, reg)) return newval except IOError: print("Error accessing 0x{}: Chcekcyour I2C address".format(self._addr)) return -1 def readFull(self, reg = 0x8C): """ Read visible + IR diode from the TSL2561 I2C device """ return self.readWord(reg) def readIR(self, reg = 0x8E): """ Reads only IR diode from the TSL2561 I2C device """ return self.readWord(reg) def readLux(self, gain = 0): """ Grabs a lux reading either with autoranging (gain=0) or with specific gain (1, 16) """ if (self.debug): print ("gain=",gain) if (gain == 1 or gain == 16): self.setGain(gain) # Low/High Gain ambient = self.readFull() IR = self.readIR() elif (gain == 0): # Auto gain self.setGain(16) # First try highGain ambient = self.readFull() if (ambient < 65535): IR = slef.readIR() if (ambient >= 65535 or IR >= 65535): # Value(s) exeed(s) datarange self.setGain(1) # Set low Gain ambient = self.readFull() IR = self.readIR() # If either sensor is saturated, no acculate lux value can be achieved. if (ambient == 0xffff or IR == 0xffff): self._LUX = None self._ambient = None self._IR = None return (self.ambient, self.IR, self._ambient, self._IR, self._LUX) if (self.gain == 1): self._ambient = 16 * ambient # Scale 1x to 16x self._IR = 16 * IR else: self._ambient = 1 * ambient if (self.debug): print ("IR Result without scaling: ",IR) print ("IR Result: ", self._IR) print ("Ambient Result without scaling: ", ambient) print ("Ambient Result: ", self._ambient) if (self._ambient == 0): # Sometimes, the channel 0 returns 0 when dark ... self._LUX = 0.0 return (ambient, IR, self._ambient, self._IR, self._LUX) ratio = (self._IR / float(self._ambient)) if (self.debug): print ("ratio: ", ratio) if ((ratio >= 0) and (ratio <= 0.52)): self._LUX = (0.0315 * self._ambient) - (0.0593 * self._ambient * (ratio ** 1.4)) elif (ratio <= 0.65): self._LUX = (0.0229 * self._ambient) - (0.0291 * self._IR) elif (ratio <= 0.80): self._LUX = (0.0157 * self._ambient) - (0.018 * self._IR) elif (ratio <= 1.3): self._LUX = (0.00338 * self._ambient) - (0.0026 * self._IR) elif (ratio > 1.3): self._LUX = 0 return (ambient, IR, self._ambient, self._IR, self._LUX) def _control(self, params): if (params == _POWER_UP): print ("Power ON") elif (params == _POWER_DOWN): print ("Power OFF") cmd = _CMD | _REG_CONTROL | params self._write_byte(self._addr, cmd) # select command register and power on time.sleep(0.4) # Wait for 400ms to power up or power down. def _partno_revision(self): """ Read Partnumber and revision of the sensor """ cmd = _CMD | _REG_ID value = self._read_byte(cmd) print ("value=",value) part = str(value)[7:4] if (part == "0000"): PartNo = "TSL2560CS" elif (part == "0001"): PartNo = "TSL2561CS" elif (part == "0100"): PartNo = "TSL2560T/FN/CL" else: PartNo = "not TSL2560 or TSL2561" RevNo = str(value)[3:0] if (self.debug): print ("response: ", value) print ("PartNo = ", PartNo) print ("RevNo = ", RevNo) return (PartNo, RevNo)
class GroveI2cColorSensorV2: """Driver for Grove I2C Color Sensor (TCS34725)""" def __init__(self, bus=None, address=0x29): self.address = address self.bus = Bus(bus) self.awake = False if self.id not in (0x44, 0x4D): raise ValueError('Not find a Grove I2C Color Sensor V2') self.set_integration_time(24) self.set_gain(4) def wakeup(self): enable = self._read_byte(_ENABLE) self._write_byte(_ENABLE, enable | _PON | _AEN) time.sleep(0.0024) self.awake = True def sleep(self): enable = self._read_byte(_ENABLE) self._write_byte(_ENABLE, enable & ~_PON) self.awake = False def is_awake(self): return self._read_byte(_ENABLE) & _PON def set_wait_time(self, t): pass @property def id(self): return self._read_byte(_ID) @property def integration_time(self): steps = 256 - self._read_byte(_ATIME) return steps * 2.4 def set_integration_time(self, t): """Set the integration time of the sensor""" if t < 2.4: t = 2.4 elif t > 614.4: t = 614.4 steps = int(t / 2.4) self._integration_time = steps * 2.4 self._write_byte(_ATIME, 256 - steps) @property def gain(self): """The gain control. Should be 1, 4, 16, or 60. """ return _GAINS[self._read_byte(_CONTROL)] def set_gain(self, gain): if gain in _GAINS: self._write_byte(_CONTROL, _GAINS.index(gain)) @property def raw(self): """Read RGBC registers return 16 bits red, green, blue and clear data """ if not self.awake: self.wakeup() while not self._valid(): time.sleep(0.0024) data = tuple( self._read_word(reg) for reg in (_RDATA, _GDATA, _BDATA, _CDATA)) return data @property def rgb(self): """Read the RGB color detected by the sensor. Returns a 3-tuple of red, green, blue component values as bytes (0-255). """ r, g, b, clear = self.raw if clear: r = int(255 * r / clear) g = int(255 * g / clear) b = int(255 * b / clear) else: r, g, b = 0, 0, 0 return r, g, b def _valid(self): """Check if RGBC is valid""" return self._read_byte(_STATUS) & 0x01 def _read_byte(self, address): command = _CMD | address return self.bus.read_byte_data(self.address, command) def _read_word(self, address): command = _CMD | _AUTO | address return self.bus.read_word_data(self.address, command) def _write_byte(self, address, data): command = _CMD | address self.bus.write_byte_data(self.address, command, data) def _write_word(self, address, data): command = _CMD | _AUTO | address data = [(data >> 8) & 0xFF, data & 0xFF] self.bus.write_i2c_block_data(self.address, command, data)
class GroveOledDisplay128x64(object): HORIZONTAL = 0x00 VERTICAL = 0x01 PAGE = 0x02 def __init__(self, bus=None, address=0x3C): self.bus = Bus(bus) self.address = address self.off() self.inverse = False self.mode = self.HORIZONTAL self.width = 128 # test self.height = 64 # test self._pages = self.height//8 # test self._buffer = [0]*(self.width*self._pages) # test self.clear() self.on() def on(self): self.send_command(_DISPLAY_ON) def off(self): self.send_command(_DISPLAY_OFF) def send_command(self, command): self.bus.write_byte_data(self.address, _COMMAND_MODE, command) def send_data(self, data): self.bus.write_byte_data(self.address, _DATA_MODE, data) def send_commands(self, commands): for c in commands: self.send_command(c) def clear(self): self.off() self._buffer = [0]*(self.width*self._pages) self.adf_display() self.on() self.set_cursor(0, 0) @property def inverse(self): return self._inverse @inverse.setter def inverse(self, enable): self.send_command(_INVERSE_DISPLAY if enable else _NORMAL_DISPLAY) self._inverse = enable @property def mode(self): return self._mode @mode.setter def mode(self, mode): self.send_command(0x20) self.send_command(mode) self._mode = mode def set_cursor(self, row, column): self.send_command(0xB0 + row) self.send_command(0x00 + (8*column & 0x0F)) self.send_command(0x10 + ((8*column>>4)&0x0F)) def putc(self, c): C_add = ord(c) if C_add < 32 or C_add > 127: # Ignore non-printable ASCII characters c = ' ' C_add = ord(c) for i in range(0, 8): self.send_data(BasicFont[C_add-32][i]) def puts(self, text): for c in text: self.putc(c) def adf_image(self, image): """Set buffer to value of Python Imaging Library image. The image should be in 1 bit mode and a size equal to the display size. """ if image.mode != '1': raise ValueError('Image must be in mode 1.') imwidth, imheight = image.size if imwidth != 128 or imheight != 64: raise ValueError('Image must be same dimensions as display (128x64).') # Grab all the pixels from the image, faster than getpixel. pix = image.load() # Iterate through the memory pages index = 0 for page in range(self._pages): # Iterate through all x axis columns. for x in range(self.width): # Set the bits for the column of pixels at the current position. bits = 0 # Don't use range here as it's a bit slow for bit in [0, 1, 2, 3, 4, 5, 6, 7]: bits = bits << 1 bits |= 0 if pix[(x, page*8+7-bit)] == 0 else 1 # Update buffer byte and increment to next byte. self._buffer[index] = bits index += 1 def adf_display(self): """Write display buffer to physical display.""" # self.command(SSD1306_COLUMNADDR) # self.command(0) # Column start address. (0 = reset) # self.command(self.width-1) # Column end address. # self.command(SSD1306_PAGEADDR) # self.command(0) # Page start address. (0 = reset) # self.command(self._pages-1) # Page end address. # Write buffer data. for i in range(0, len(self._buffer), 16): control = 0x40 # Co = 0, DC = 0 #self._i2c.writeList(control, self._buffer[i:i+16]) #self._bus.write_i2c_block_data(self._address, register, data) #self.bus.write_byte_data(self.address, _DATA_MODE, data) self.bus.write_i2c_block_data(self.address, _DATA_MODE, self._buffer[i:i+16]) def show_image(self, image): #im = image #Image.open(image) #bw = im.convert('1') pixels = np.array(image.getdata()) #pixels = image.load() page_size = 128 * 8 self.set_cursor(0, 0) # iterate through pages for page in range(8): start = page_size * page end = start + page_size # iterate through x-axis columns for i in range(start, start + 128): data = np.packbits(pixels[i:end:128][::-1])[0] self.send_data(data)