class Device(object): def __init__(self, address, bus): self._bus = SMBus(bus) self._address = address def writeRaw8(self, value): value = value & 0xff self._bus.write_byte(self._address, value) def readRaw8(self): result = self._bus.read_byte(self._address) & 0xff return result def write8(self, register, value): value = value & 0xff self._bus.write_byte_data(self._address, register, value) def readU8(self, register): result = self._bus.read_byte_data(self._address, register) & 0xFF return result def readS8(self, register): result = self.readU8(register) if result > 127: result -= 256 return result def write16(self, register, value): value = value & 0xffff self._bus.write_word_data(self._address, register, value) def readU16(self, register, little_endian = True): result = self._bus.read_word_data(self._address,register) & 0xFFFF if not little_endian: result = ((result << 8) & 0xFF00) + (result >> 8) return result def readS16(self, register, little_endian = True): result = self.readU16(register, little_endian) if result > 32767: result -= 65536 return result def writeList(self, register, data): self._bus.write_i2c_block_data(self._address, register, data) def readList(self, register, length): results = self._bus.read_i2c_block_data(self._address, register, length) return results
class veml6075: def __init__(self, addr=0x10): self.i2c = SMBus(1) self.addr = addr self.i2c.write_byte_data(self.addr, 0x00, (0 & 7) << 4) self.a = 2.22 self.c = 2.95 self.b = 1.33 self.d = 1.74 self.UVAresp = 0.001461 self.UVBresp = 0.002591 self.UVA2Wm = 1 / 93 self.UVB2Wm = 1 / 210 def read(self): UVA = self.i2c.read_word_data(self.addr, 0x07) UVB = self.i2c.read_word_data(self.addr, 0x09) UVcomp1 = self.i2c.read_word_data(self.addr, 0x0A) UVcomp2 = self.i2c.read_word_data(self.addr, 0x0B) UVAcalc = UVA - (self.a * UVcomp1) - (self.b * UVcomp2) UVBcalc = UVB - (self.c * UVcomp1) - (self.d * UVcomp2) UVAI = UVAcalc * self.UVAresp UVBI = UVBcalc * self.UVBresp UVI = (UVAI + UVBI) / 2 UVAWm = UVAcalc * self.UVA2Wm UVBWm = UVBcalc * self.UVB2Wm return UVI
class RHTS: """ Driver for Si7021 temperatuer and humidity sensor """ meas_RH = 0xf5 read_temp = 0xe0 reset = 0xfe def __init__(self, i2cbus, addr): self.i2cbus = i2cbus self.bus = SMBus(self.i2cbus) self.addr = addr def measure(self): self.bus.write_byte(self.addr, self.meas_RH) sleep(0.3) def readall(self): """Units of temperature in deg C """ self.measure() # Pull the MSB of the RH data data0 = self.bus.read_byte(self.addr) # Pull the LSB from the RH data data1 = self.bus.read_byte(self.addr) # Calculate the RH from user manual section 5.1.1 RH = ((data0*256 + data1)*125 / 65535.0)-6 self.RH = max(0, min(100, RH)) # Pull the two byte temperature dats - needs byte shifting data3 = self.bus.read_word_data(self.addr, self.read_temp) # Shift the bytes data4 = ((data3 & 0xff) << 8) | (data3 >> 8) # Calculate the temperature in deg C from manual section 5.1.1 self.tempC = 175.72 * data4 / 65536. - 46.85 # return the RH and Temperature data return [self.tempC, self.RH]
class TemperatureSensor(): """ Read temperature using NXT Temperature sensor """ def __init__(self): # Set LEGO port for NXT Temp sensor lego_port = LegoPort(INPUT_2) lego_port.mode = 'other-i2c' sleep(0.5) # Settings for I2C (SMBus(4) for INPUT_2) self.lego_bus = SMBus(4) # LM75 address self.address = NXT_SENSOR_ADDRESS def read_temperature_c(self): raw = self.lego_bus.read_word_data(self.address, 0) & 0xFFFF raw = ((raw << 8) & 0xFF00) + (raw >> 8) temp = (raw / 32.0) / 8.0 return temp def to_fahrenheit(self, temp): temp = (temp * (9.0 / 5.0)) + 32.0 return temp def read_temperature_f(self): temp = self.to_fahrenheit(self.read_temperature_c()) return temp
def get_temp(): # zlecenie konwersji i2c_bus = SMBus(1) i2c_bus.write_byte_data(Register.LIGHT2_ADDRESS, 10, 1) sleep(1) cel = i2c_bus.read_word_data(0x20, 5) cel = cel >> 8 return cel
def range_dist(): sonar = False lidar_sens = False # lidar sensing True, else EZ4 sonar or VL53L1X if sonar: # does not work well on grass from smbus import SMBus ## i2cbus = SMBus(1) while True: try: i2cbus = SMBus(1) i2cbus.write_byte(0x70, 0x51) time.sleep(0.12) val = i2cbus.read_word_data(0x70, 0xE1) distance_in_cm = val >> 8 | (val & 0x0F) << 8 ## print distance_in_cm, 'cm' print(distance_in_cm, 'cm', file=f) msg_sensor(distance_in_cm, 25, 400), #sonar facing down except IOError as err: print(err) time.sleep(0.1) if lidar_sens: from lidar_lite import Lidar_Lite lidar = Lidar_Lite() connected = lidar.connect(1) if connected < 0: print("\nlidar not connected") else: print("\nlidar connected") while True: dist = lidar.getDistance() print(dist, 'cm') print(dist, 'cm', file=f) msg_sensor(dist, 25, 700), #lidar facing down time.sleep(0.2) else: # does not work in sunlight import VL53L1X tof = VL53L1X.VL53L1X(i2c_bus=1, i2c_address=0x29) tof.open() # Initialise the i2c bus and configure the sensor tof.start_ranging( 2 ) # Start ranging, 1 = Short Range, 2 = Medium Range, 3 = Long Range # Short range max:1.3m, Medium range max:3m, Long range max:4m while True: distance_in_cm = tof.get_distance( ) / 10 # Grab the range in cm (mm) time.sleep(0.2) # timeout mavlink rangefinder = 500 ms print(distance_in_cm, 'cm', file=f) msg_sensor(distance_in_cm, 25, 250), #sensor facing down tof.stop_ranging() # Stop ranging
def getPowerOut(self, fromDRQ): if (fromDRQ == True): bus = SMBus(1) self.powerOut = self.decodePMBus( bus.read_word_data(self.address, 0x96)) bus.close() else: self.powerOut = self.voltageOut * self.current return self.powerOut
class MTSMBus(I2CBus): """ Multi-thread compatible SMBus bus. This is just a wrapper of SMBus, serializing I/O on the bus for use in multi-threaded context and adding _i2c_ variants of block transfers. """ def __init__(self, bus_id=1, **kwargs): """ :param int bus_id: the SMBus id (see Raspberry Pi documentation) :param kwargs: parameters transmitted to :py:class:`smbus.SMBus` initializer """ I2CBus.__init__(self, **kwargs) self._bus = SMBus(bus_id) # I/O serialization lock self._lock = threading.Lock() def read_byte(self, addr): with self._lock: return self._bus.read_byte(addr) def write_byte(self, addr, data): with self._lock: self._bus.write_byte(addr, data) def read_byte_data(self, addr, reg): with self._lock: return self._bus.read_byte_data(addr, reg) def write_byte_data(self, addr, reg, data): with self._lock: self._bus.write_byte_data(addr, reg, data) def read_word_data(self, addr, reg): with self._lock: return self._bus.read_word_data(addr, reg) def write_word_data(self, addr, reg, data): with self._lock: self._bus.write_word_data(addr, reg, data) def read_block_data(self, addr, reg): with self._lock: return self._bus.read_block_data(addr, reg) def write_block_data(self, addr, reg, data): with self._lock: self._bus.write_block_data(addr, reg, data) def read_i2c_block_data(self, addr, reg, count): with self._lock: return self._bus.read_i2c_block_data(addr, reg, count) def write_i2c_block_data(self, addr, reg, data): with self._lock: self._bus.write_i2c_block_data(addr, reg, data)
class LocalhostSMBusSlave(SMBusSlave): def __init__(self, bus, address): SMBusSlave.__init__(self, bus, address) self.bus = SMBus(bus) self.address = address #return: one byte hex string without '0x': '12' def get_byte(self, offset): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) ret = self.bus.read_byte_data(self.address, offset) time.sleep(self.interval) data = hex(ret) return data[2:].zfill(2) #input: offset:str, data:int def set_byte(self, offset, data): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) self.bus.write_byte_data(self.address, offset, data) time.sleep(self.interval) #return: two byte hex string without '0x': '1234' def get_word(self, offset): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) ret = self.bus.read_word_data(self.address, offset) data = hex(ret) time.sleep(self.interval) return data[2:].zfill(4) def set_word(self, offset, data): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) if sys.byteorder == "big": data = ((data & 0xff00) >> 8) + ((data & 0x00ff) << 8) self.bus.write_word_data(self.address, offset, data) time.sleep(self.interval) #return: hex string list per byte,without '0x' :['12', '0a'] def get_block(self, offset, length="32"): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) ret = self.bus.read_block_data(self.address, offset) time.sleep(self.interval) hex_ret = [hex(i)[2:].zfill(2) for i in ret] return hex_ret def set_block(self, offset, data): # print "%s %s" % (datetime.datetime.utcnow().strftime("%H:%M:%S.%f")[:-4], sys._getframe().f_code.co_name) data_arr = [(data & 0x00ff), ((data & 0xff00) >> 8)] #self.bus.write_i2c_block_data(self.address, offset, data_arr) self.bus.write_block_data(self.address, offset, data_arr) time.sleep(self.interval)
class PapirusTemperature: def __init__(self, i2c_bus=1): self.bus = SMBus(i2c_bus) def __read_raw(self): n = self.bus.read_word_data(0x48, 0x00) r = ((((n << 8) & 0xFF00) | ((n >> 8) & 0x00FF)) >> 5) if r > 2048: # negative r = 2048 - r return r def read_celsius(self): return self.__read_raw() * 0.125 def read_fahrenheit(self): return self.__read_raw() * 0.225 + 32
class EPuck: """Class for interfacing with a generic e-puck robot.""" def __init__(self, i2c_bus: Optional[int] = None, i2c_address: Optional[int] = None): if i2c_bus is not None: self._bus = SMBus(i2c_bus) else: try: self._bus = SMBus(_EPUCK_I2C_CHANNEL) except FileNotFoundError: self._bus = SMBus(_EPUCK_LEGACY_I2C_CHANNEL) if i2c_address is not None: self._i2c_address = i2c_address else: self._i2c_address = _EPUCK_I2C_ADDRESS GPIO.setmode(GPIO.BOARD) GPIO.setup(_EPUCK_RESET_PIN, GPIO.OUT, initial=GPIO.HIGH) def __del__(self): GPIO.cleanup(_EPUCK_RESET_PIN) def _write_data_8(self, address, data): self._bus.write_byte_data(self._i2c_address, address, data) def _write_data_16(self, address, data): self._bus.write_word_data(self._i2c_address, address, data) def _read_data_8(self, address): return self._bus.read_byte_data(self._i2c_address, address) def _read_data_16(self, address): return self._bus.read_word_data(self._i2c_address, address) @staticmethod def reset_robot(): GPIO.output(_EPUCK_RESET_PIN, GPIO.LOW) sleep(0.1) GPIO.output(_EPUCK_RESET_PIN, GPIO.HIGH)
def range_dist(): sonar=False lidar_sens=True # lidar sensing True, else EZ4 sonar or VL53L1X if sonar: # does not work well on grass from smbus import SMBus ## i2cbus = SMBus(1) while True: try: i2cbus = SMBus(1) i2cbus.write_byte(0x70, 0x51) time.sleep(0.12) val = i2cbus.read_word_data(0x70, 0xE1) distance_in_cm=val>>8 | (val & 0x0F)<<8 ## print distance_in_cm, 'cm' print>>f,distance_in_cm,'cm' msg_sensor(distance_in_cm,25,400), #sonar facing down except IOError, err: print err time.sleep(0.1)
from smbus import SMBus b = SMBus(1) # 1 indicates /dev/i2c-1 dev_addr1 = 0x10 dev_addr2 = 0x11 general_purpose_register = 0x03 dac_pin_config_register = 0x05 dac_out0_register = 0x10 # set I/O0 of dev 0 to dac output b.write_word_data(dev_addr1, dac_pin_config_register, 0x0001) # set I/O0 to 1000/4095 -> 0x3e8 b.write_word_data(dev_addr1, dac_out0_register, 0x83e8) print("{:x}".format(b.read_word_data(dev_addr1, general_purpose_register)))
class Machine: def __init__(self) -> None: self.currentState = Outputs(Motor.Halt, Plate.Off) self.bus = SMBus(1) def getSensorValues(self) -> Inputs: temp = self.tryRead(self.readObjectTempStable) top = self.readPin(TOUCH_SENSOR_TOP_PIN) bottom = self.readPin(TOUCH_SENSOR_BOTTOM_PIN) back = self.readPin(TOUCH_SENSOR_BACK_PIN) return Inputs(top=top, bottom=bottom, back=back, temp=temp) def controlDevices(self, controls: Outputs, force: bool = False) -> None: if force or controls.motor != self.currentState.motor: print(controls.motor) if controls.motor == Motor.Up: self.motorUp() if controls.motor == Motor.Down: self.motorDown() if controls.motor == Motor.Halt: self.motorHalt() if controls.plate != self.currentState.plate: self.switchPlateState() self.currentState = Outputs(controls.motor, controls.plate) def readPin(self, pin: int) -> bool: return GPIO.input(pin) def motorUp(self) -> None: GPIO.output(MOTOR_A_PIN, GPIO.LOW) GPIO.output(MOTOR_B_PIN, GPIO.HIGH) GPIO.output(MOTOR_E_PIN, GPIO.HIGH) def motorDown(self) -> None: GPIO.output(MOTOR_A_PIN, GPIO.HIGH) GPIO.output(MOTOR_B_PIN, GPIO.LOW) GPIO.output(MOTOR_E_PIN, GPIO.HIGH) def motorHalt(self) -> None: GPIO.output(MOTOR_A_PIN, GPIO.LOW) GPIO.output(MOTOR_B_PIN, GPIO.LOW) GPIO.output(MOTOR_E_PIN, GPIO.LOW) def turnRelayOn(self) -> None: GPIO.output(RELAY_PIN, GPIO.HIGH) def turnRelayOff(self) -> None: GPIO.output(RELAY_PIN, GPIO.LOW) def switchPlateState(self) -> None: self.turnRelayOn() time.sleep(PLATE_SWITCH_TIMEOUT) self.turnRelayOff() def getAverage(self, values: List[float]) -> float: return sum(values) / len(values) def read16(self, register: int) -> float: return self.bus.read_word_data(ADDRESS, register) def readTemp(self, register: int) -> float: return self.read16(register) * 0.02 - 273.15 def readTempStable(self, register: int) -> float: values: List[float] = [] numTries = 0 while len(values) < NUM_VALUES_TO_AVERAGE_OVER: numTries += 1 try: time.sleep(TIME_BETWEEN_TRIES) values.append(self.readTemp(register)) except IOError as err: if numTries >= MAX_NUM_TRIES: raise err continue error = max(values) - min(values) if error > MAX_ALLOWED_ERROR: raise InaccuracyError("High temperature deviation") return self.getAverage(values) def readObjectTempStable(self) -> float: return self.readTempStable(REGISTER_OBJECT_TEMP) def tryRead(self, readFunc: Callable[..., float]) -> float: try: return readFunc() except IOError as err: print("IO error") raise err except InaccuracyError as err: print("Inaccuracy error") raise err return 0 def __enter__(self) -> None: GPIO.setmode(GPIO.BOARD) GPIO.setup(RELAY_PIN, GPIO.OUT) GPIO.setup(MOTOR_A_PIN, GPIO.OUT) GPIO.setup(MOTOR_B_PIN, GPIO.OUT) GPIO.setup(MOTOR_E_PIN, GPIO.OUT) GPIO.setup(TOUCH_SENSOR_TOP_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(TOUCH_SENSOR_BOTTOM_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) GPIO.setup(TOUCH_SENSOR_BACK_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) return self def __exit__(self, type: Any, value: Any, traceback: Any) -> Any: """Make sure we turn the plate off and clean up GPIO pins whenever we shut down.""" self.motorHalt() if self.currentState.plate == Plate.On: self.switchPlateState() GPIO.cleanup()
#!/usr/bin/env python2.7 from smbus import SMBus import time bus = SMBus(1) addr = 0x0b t_end = time.time() + 60 * 15 while time.time() < t_end: try: voltage = bus.read_word_data(addr, 0x09) current = bus.read_word_data(addr, 0x0a) #temperature = bus.read_word_data(addr, 0x08) relsoc = bus.read_word_data(addr, 0x0d) adssoc = bus.read_byte_data(addr, 0x0e) except: continue print("Voltage: ") print(voltage) print("Current: ") print(current) print("Relsoc: ") print(relsoc) print("Adssoc: ") print(adssoc) time.sleep(1)
class MLX90614_IR_sensor(): '''This class will read the IR temperatue values from the sensor''' def __init__(self, address): '''Initalizing all variables ''' #address working at self.address = address #note that the default slave address is 0x00 #TODO: how to detect several different addresses at once #self.address = 0x5a #Objec temperature address self.tobj_address = 0x27 #0x27 #ambien temperature address self.tamb_address = 0x26 #0x26 #smbus command setup self.bus = SMBus(1) #inital ambient and object temperatures self.init_tamb_value = 0.0 self.init_tobj_value = 0.0 #inital tamb and tobj values converted to Celsius self.tamb_ans= 0.0 self.tobj_ans= 0.0 #ambient temperature self.tamb_num = 0.0 #object temperature self.tobj_num = 0.0 self.tobj_percent_limit_up=0.0 self.tobj_percent_limit_down=0.0 self.tamb_percent_limit_up=0.0 self.tamb_percent_limit_down=0.0 #instantiate the config file and extract the dict #opening the config file self.config = config.config.Config() #reading the config file #self.config.readconfig() #extract the slice and slice values #print self.config.dict #dict length for data analysis self.length = int(self.config.dict['length']) #slice length of data analysis self.slice = int(self.config.dict['slice']) #importing the control_variable() class to obtain the jump and limit values self.control_class = mlx.control_variable.Control_Variable() self.control_class.run() self.tobj_jump_value = 0.0 self.tamb_jump_value = 0.0 self.cycle = 0 self.counter = 0 self.tamb_data_analysis_list = [] self.tobj_data_analysis_list = [] self.tobj_data_analysis_result = [] self.tamb_data_analysis_result = [] #this is the record_list which is the varible passed to the gui #note that we are initalizing all variables with 0 are the six variables are there #the appended list data is being stored to the log files, the gui will only show a subaspect of the data self.record_list = [0,0,0,0,0,0] self.record_dict = {self.address: []} #, 'cycle':self.cycle } def read(self): '''getting the values from the IR device sensor''' self.init_tobj_value = self.bus.read_word_data(self.address, self.tobj_address) #sleep for 200 ms the time for the sensor is at least 144 ms time.sleep(0.2) self.init_tamb_value = self.bus.read_word_data(self.address, self.tamb_address) #sleep for 200 ms the timer for the sensor is at least 144 ms time.sleep(0.2) def object_temp_analysis(self): '''this function converts the object temperature from kelvin to celsius values''' #converting values from long bits into degrees celsius #using fomula in sensor datasheet manual #pg ????? #convert temperatures from kelvin to celsius tobj_ans = ( self.init_tobj_value*0.02 ) - 273.15 #print tobj_ans self.tobj_ans = tobj_ans #mylog2.debug('Tobj: ' + repr(tobj_ans) ) #calculate jump value jump_value = tobj_ans - self.tobj_num #- tobj_ans #save calculated jump value to self value self.tobj_jump_value = jump_value #print 'obj jump: ', jump_value mylog2.debug('obj jump value: ' + repr(jump_value) ) #comparing jump value to control jump value set by user if jump_value >= self.control_class.jump_value: #reinitalize variables self.tobj_num = tobj_ans #calculate percent limit self.tobj_percent_limit_up = self.tobj_num*self.control_class.limit_value print '*****TOBJ UP*****' mylog2.debug('UP VALUE-Tobj:--> ' + 'object temperature value: '+ repr(self.tobj_num) + 'jump up value: ' + repr(jump_value) +'temp limit value: ' + repr(self.tobj_percent_limit_up) + 'jump value: ' + repr(self.control_class.jump_value) ) elif jump_value <= -(self.control_class.jump_value): #reinitalize variables self.tobj_num = tobj_ans #calculating percent limit self.tobj_percent_limit_down = self.tobj_num*self.control_class.limit_value print '******TOBJ DOWN*****' mylog2.debug('DOWN VALUE-Tobj:--> ' + 'object temperature value: '+ repr(self.tobj_num) + 'jump up value: ' + repr(jump_value) +'temp limit value: ' + repr(self.tobj_percent_limit_down) +'jump value: ' + repr(self.control_class.jump_value)) else: print 'no change' def ambient_temp_analysis(self): '''this function records the ambient temperatuer and converts the value to degrees celsisus ''' tamb_ans = ( self.init_tamb_value*0.02 ) - 273.15 #print tamb_ans #mylog2.debug('tamb ans: ' + repr(tamb_ans) ) self.tamb_ans = tamb_ans #calculate jump value jump_value = tamb_ans - self.tamb_num #- tamb_ans #print 'amb jump: ', jump_value if jump_value >= self.control_class.jump_value: #assuming the value is + #reinitalize varialbes self.tamb_num = tamb_ans #calculate percent limit tamb_percent_limit_up = self.tamb_num*self.control_class.limit_value print '*********TAMB UP***********' mylog2.debug('UP VALUE-Tamb:-->' + 'Ambient temperature value: '+ repr(self.tamb_num) + 'jump up value: ' + repr(jump_value) +'temp limit value: ' + repr(self.tamb_percent_limit_up) + 'jump value: ' + repr(self.control_class.jump_value)) elif jump_value <= -(self.control_class.jump_value): #reinitalize variables self.tamb_num = tamb_ans #calculate percent limit tamb_percent_limit_down = self.tamb_num*self.control_class.limit_value print '*********TAMB DOWN***********' mylog2.debug('DOWN VALUE-Tamb' + 'Ambient temperature value: '+ repr(self.tamb_num) + 'jump up value: ' + repr(jump_value) +'temp limit value: ' + repr(self.tamb_percent_limit_down) + 'jump value: ' + repr(self.control_class.jump_value)) else: print 'no change' def data_analysis(self): '''This function does the data analysis for the data ''' #appending items to list self.tobj_data_analysis_list.append(self.tobj_ans) #_num) self.tamb_data_analysis_list.append(self.tamb_ans) #num) if len(self.tobj_data_analysis_list) > self.length: #15: #if the length is greater then 50 for item in self.tobj_data_analysis_list[:self.slice]: #10]: #take out the first 20 items and pop them out self.tobj_data_analysis_list.pop(0) if len(self.tamb_data_analysis_list) > self.length: #15: #pop out the first 20 items in the list for item in self.tamb_data_analysis_list[:self.slice]: #10]: self.tamb_data_analysis_list.pop(0) #doing tobject calculations tobj_min = min(self.tobj_data_analysis_list[ -self.slice: ] ) #[-5:]) tobj_max = max(self.tobj_data_analysis_list[ -self.slice: ] ) #[-5:]) tobj_sum = sum(self.tobj_data_analysis_list[ -self.slice: ] ) #[-5:]) tobj_len = len(self.tobj_data_analysis_list) #[ -self.slice: ] ) #[-5:]) tobj_avg = tobj_sum/tobj_len #doign tambient claculations tamb_min = min(self.tamb_data_analysis_list[ -self.slice: ] ) #[-5:]) tamb_max = max(self.tamb_data_analysis_list[ -self.slice: ] ) #[-5:]) tamb_sum = sum(self.tamb_data_analysis_list[ -self.slice: ] ) #[-5:]) tamb_len = len(self.tamb_data_analysis_list) #[ -self.slice: ] ) #[-5:]) tamb_avg = tamb_sum/tobj_len self.record_list=[tobj_min, tobj_max, tobj_avg, tamb_min, tamb_max, tamb_avg, tobj_len, tamb_len] #logging the data mylog2.debug('Record list: ' + repr(self.record_list) ) def record_data(self): '''this function saves the data to csv files note that this data is not needed and necessary TODO: Deprecated function ''' myfile = open(FILENAME, 'a') newrow = time.strftime('%H:%M:%S,') newrow += str(self.cycle) + "," newrow += str(self.address) + "," newrow += str(self.tobj_ans) + "," newrow += str(self.tamb_ans) newrow += NEWLINE myfile.write(newrow) myfile.close() def run(self): ''''Function which runs the value''' #runt the control class to ensure the varaibles are set right and can be changed as needed #self.control_class.run() mylog2.debug('control variable values: ' + repr(self.control_class.jump_value) + "--" + repr(self.control_class.limit_value) ) self.cycle+=1 print print 'Time: ', time.strftime('%H:%M:%S,') print 'cycle: ', self.cycle self.read() self.object_temp_analysis() self.ambient_temp_analysis() self.data_analysis() self.record_data() print 'Address: %s -- tobject: %s -- tambient: %s'%(self.address, self.tobj_num, self.tamb_num) #log the results mylog2.debug('tamb data analysis: ' + repr(self.tamb_data_analysis_result) )
class ads1015: def __init__(self, addr=0x48): self.i2c = SMBus(1) self.addr = addr self.constants() self.mux = self.get(self.MUX) self.gain = self.get(self.GAIN) self.mode = self.get(self.MODE) self.data_rate = self.get(self.DATA_RATE) self.comp_mode = self.get(self.COMP_MODE) self.comp_pol = self.get(self.COMP_POL) self.comp_lat = self.get(self.COMP_LAT) self.comp_que = self.get(self.COMP_QUE) def constants(self): # Register adresses self.CONV_REG = 0b00 self.CONFIG_REG = 0b01 self.LO_TRESH_REG = 0b10 self.HI_TRESH_REG = 0b11 # Input MUX self.MUX = (12, 3, 'mux') self.MUX_DIFF_01 = 0b000 self.MUX_DIFF_03 = 0b001 self.MUX_DIFF_13 = 0b010 self.MUX_DIFF_23 = 0b011 self.MUX_0 = 0b100 self.MUX_1 = 0b101 self.MUX_2 = 0b110 self.MUX_3 = 0b111 # Gain self.GAIN = (9, 3, 'gain') self.GAIN_0 = 0b000 # +/-6.144V self.GAIN_1 = 0b001 # +/-4.096V self.GAIN_2 = 0b010 # +/-2.048V self.GAIN_3 = 0b011 # +/-1.024V self.GAIN_4 = 0b100 # +/-0.512V self.GAIN_5 = 0b101 # +/-0.256V self.VRANGE = [6.144, 4.096, 2.048, 1.024, 0.512, 0.256] # Conversion mode self.MODE = (8, 1, 'mode') self.MODE_CONTINUOUS = 0b0 self.MODE_SINGLE_SHOT = 0b1 # Data rate self.DATA_RATE = (5, 3, 'data_rate') self.DATA_RATE_128SPS = 0b000 self.DATA_RATE_250SPS = 0b001 self.DATA_RATE_490SPS = 0b010 self.DATA_RATE_920SPS = 0b011 self.DATA_RATE_1600SPS = 0b100 self.DATA_RATE_2400SPS = 0b101 self.DATA_RATE_3300SPS = 0b110 # Comperator mode self.COMP_MODE = (4, 1, 'comp_mode') self.COMP_MODE_NORMAL = 0b0 self.COMP_MODE_WINDOW = 0b1 # Comperator polarity self.COMP_POL = (3, 1, 'comp_pol') self.COMP_POL_NORMAL = 0b0 self.COMP_POL_INVERTED = 0b1 # Comperator latching self.COMP_LAT = (2, 1, 'comp_lat') self.COMP_LAT_OFF = 0b0 self.COMP_LAT_ON = 0b1 # Comperator queue self.COMP_QUE = (0, 2, 'comp_que') self.COMP_QUE_1 = 0b00 self.COMP_QUE_2 = 0b01 self.COMP_QUE_4 = 0b10 self.COMP_QUE_OFF = 0b11 def bitwrite16(self, word, value, bitshift, bitwidth): return ((word & (0xFFFF - ((2**bitwidth - 1) << bitshift))) | (value << bitshift)) def byteswap(self, word): return ((word >> 8) & 0x00FF) + ((word << 8) & 0xFF00) def get(self, parameter): config = self.byteswap( self.i2c.read_word_data(self.addr, self.CONFIG_REG)) return (config >> parameter[0]) & (2**parameter[1] - 1) def set(self, parameter, value): config = self.byteswap( self.i2c.read_word_data(self.addr, self.CONFIG_REG)) config = self.bitwrite16( config, value, bitshift=parameter[0], bitwidth=parameter[1]) & 0x7FFF self.i2c.write_word_data(self.addr, self.CONFIG_REG, self.byteswap(config)) setattr(self, parameter[2], value) def convert(self): config = self.byteswap( self.i2c.read_word_data(self.addr, self.CONFIG_REG)) config = config | 0x8000 self.i2c.write_word_data(self.addr, self.CONFIG_REG, self.byteswap(config)) def isconverting(self): config = self.byteswap( self.i2c.read_word_data(self.addr, self.CONFIG_REG)) return ((config & 0x8000) == 0) def read(self, mux=None): if mux in [0, 1, 2, 3, 4, 5, 6, 7]: self.set(self.MUX, mux) if self.mode == self.MODE_SINGLE_SHOT: self.convert() while self.isconverting(): pass return self.byteswap(self.i2c.read_word_data(self.addr, self.CONV_REG)) def voltage(self, mux=None): return self.read(mux) * self.VRANGE[self.gain] / 0x7FFF def set_input(self, pin=None): if pin in [0, 1, 2, 3]: self.set(self.MUX, pin + 4) def set_gain(self, gain=None): if gain in [0, 1, 2, 3, 4, 5]: self.set(self.GAIN, gain)
def _readWordPMBus(self, cmd, pecByte=True): bus = SMBus(self.busID) bus.pec = pecByte data = bus.read_word_data(self.address, cmd) bus.close() return data
I2CAdress = 0x40 # command codes ( datasheet_Sensirion_Humidity_Sensors_SHT21_Datasheet_V4.pdf __page 8 __ Table 6 ) TEM = 0xE3 HUM = 0xE5 WRITE_USER_REGISTER = 0xE6 READ_USER_REGISTER = 0xE7 # command codes special ( datasheet_Sensirion_Humidity_Sensors_SHT2x_Electronic_Identification_Code_V1.1 ) CMD_ID = 0xFA0F #THe I2C bus use on raspberry PI3 bus = SMBus(1) #reading the identification numbers ID_number = bus.read_word_data(I2CAdress, CMD_ID) print format(ID_number, '04x') sleep(0.1) # Set the resolution to better possible : 0x02 --> 14 bits for temperature and 12 bits for humidity (datasheet_Sensirion_Humidity_Sensors_SHT21_Datasheet_V4.pdf __page 9 __ Table 8) bus.write_byte_data(I2CAdress, WRITE_USER_REGISTER, 0x02) # Read the user register for see if the resolution is like the specification user_register = bus.read_byte_data(I2CAdress, READ_USER_REGISTER) print format(user_register, '02x') # reading raw humidity registers raw_humidity = bus.read_word_data(I2CAdress, HUM) data_humidity = [(raw_humidity & 0xFF), ((raw_humidity >> 8) & 0xFF)] #print data_humidity # reading raw temperature registers
class bq34z100g1(object): def __init__(self, address=0x55, bus=1): self._address = address self._bus = SMBus(bus) @staticmethod def log(msg): print(msg) @staticmethod def ftol(byte: int): liste = [] liste.append(1) if byte & 1 > 0 else liste.append(0) liste.append(1) if byte & 2 > 0 else liste.append(0) liste.append(1) if byte & 4 > 0 else liste.append(0) liste.append(1) if byte & 8 > 0 else liste.append(0) liste.append(1) if byte & 16 > 0 else liste.append(0) liste.append(1) if byte & 32 > 0 else liste.append(0) liste.append(1) if byte & 64 > 0 else liste.append(0) liste.append(1) if byte & 128 > 0 else liste.append(0) return liste def openConfig(self): self._bus.write_word_data(self._address, 0x00, 0x0414) self._bus.write_word_data(self._address, 0x00, 0x3672) self._bus.write_byte_data(self._address, 0x61, 0x00) def setConfig(self): self.openConfig() self._bus.write_byte_data(self._address, 0x3e, 0x30) self._bus.write_byte_data(self._address, 0x3f, 0x00) # self._bus.write_byte_data(self._address, 0x4a, 0x00) # self._bus.write_byte_data(self._address, 0x4b, 0x00) def _writeValue(self, cmd, text): try: self._bus.write_word_data(self._address, cmd, text) except: bq34z100g1.log("Couldn't write to i2c bus") def _readValue(self, register: int, length: int = 2) -> int: try: if length == 2: return self._bus.read_word_data(self._address, register) if length == 1: return self._bus.read_byte_data(self._address, register) else: print("is not supported by now") # do again two times? return -1 except: bq34z100g1.log("Could not read i2c bus") return -1 def _readSignedValue(self, register: int, length: int = 2) -> int: value = self._readValue(register, length) if length == 2: if value <= 32767: return value else: return value - 65535 if length == 1: if value <= 128: return value else: return value - 256 def get_temperature(self): # 0x0c """returns Temperature in °C""" return round((self._readValue(0x0C) * 0.1) - 273.15, 2) def get_internal_temperature(self): # 0x2a """return internal Temperature in °C""" return round((self._readValue(0x2A) * 0.1) - 273.15, 2) def get_voltage(self): # 0x08,0x09 """return Voltage in mV""" return self._readValue(0x08) def get_current(self): # 0x10,0x11 """returns Current in mA""" return self._readSignedValue(0x10) def get_power(self): # 0x26,0x27 """returns current Power Usage""" return self._readSignedValue(0x26) def get_capacity(self): # 0x04,0x05 """returns Capacity in mAh""" return self._readValue(0x04) def get_full_capacity(self): # 0x06,0x07 """returns Capacity when full in mAh""" return self._readValue(0x06) def get_design_capacity(self): # 0x0c,0x0d """returns Design Capacity in mAh""" return self._readValue(0x3C) def get_cycle_count(self): # 0x2c """returns the amount of Cycles the Battery has run""" return self._readValue(0x2C, 1) def get_state_of_charge(self): # 0x02 """return State of Charge in %""" return self._readValue(0x02, 1) def get_flagsa(self): #0x0e, 0x0f return str(str(self.ftol(int(self._readValue(0x0e, 1)))) + "\n" + str(self.ftol(int(self._readValue(0x0f, 1))))) def get_flagsb(self): #0x12, 0x13 return str(str(self.ftol(int(self._readValue(0x12, 1)))) + "\n" + str(self.ftol(int(self._readValue(0x13, 1))))) def get_ctrl_statusa(self): return self.ftol(int(self._readValue(0x00, 1))) def get_ctrl_statusb(self): return self.ftol(int(self._readValue(0x01, 1))) def get_max_error(self): return self._readValue(0x03, 1) def get_avg_time_to_empty(self): return self._readValue(0x18) def get_avg_time_to_full(self): # 0x1a,0x1b return self._readValue(0x1A) def get_state_of_health(self): # 0x2e,0x2f return self._readValue(0x2E) def get_qmax_time(self): return self._readValue(0x74) def get_learned_status(self): return self.ftol(int(self._readValue(0x63,1)))
class PanTilt: """PanTilt HAT Driver Communicates with PanTilt HAT over i2c to control pan, tilt and light functions """ REG_CONFIG = 0x00 REG_SERVO1 = 0x01 REG_SERVO2 = 0x03 REG_WS2812 = 0x05 REG_UPDATE = 0x4E UPDATE_WAIT = 0.03 NUM_LEDS = 24 def __init__( self, enable_lights=True, idle_timeout=2, # Idle timeout in seconds light_mode=WS2812, light_type=RGB, servo1_min=575, servo1_max=2325, servo2_min=575, servo2_max=2325, address=0x15, i2c_bus=None): self._is_setup = False self._idle_timeout = idle_timeout self._servo1_timeout = None self._servo2_timeout = None self._i2c_retries = 10 self._i2c_retry_time = 0.01 self._enable_servo1 = False self._enable_servo2 = False self._enable_lights = enable_lights self._light_on = 0 self._servo_min = [servo1_min, servo2_min] self._servo_max = [servo1_max, servo2_max] self._light_mode = light_mode self._light_type = light_type self._i2c_address = address self._i2c = i2c_bus def setup(self): if self._is_setup: return True if self._i2c is None: try: from smbus import SMBus self._i2c = SMBus(1) except ImportError: if version_info[0] < 3: raise ImportError( "This library requires python-smbus\nInstall with: sudo apt-get install python-smbus" ) elif version_info[0] == 3: raise ImportError( "This library requires python3-smbus\nInstall with: sudo apt-get install python3-smbus" ) self.clear() self._set_config() atexit.register(self._atexit) self._is_setup = True def _atexit(self): if self._servo1_timeout is not None: self._servo1_timeout.cancel() if self._servo2_timeout is not None: self._servo2_timeout.cancel() self._enable_servo1 = False self._enable_servo2 = False self._set_config() def idle_timeout(self, value): """Set the idle timeout for the servos Configure the time, in seconds, after which the servos will be automatically disabled. :param value: Timeout in seconds """ self._idle_timeout = value def _set_config(self): """Generate config value for PanTilt HAT and write to device.""" config = 0 config |= self._enable_servo1 config |= self._enable_servo2 << 1 config |= self._enable_lights << 2 config |= self._light_mode << 3 config |= self._light_on << 4 self._i2c_write_byte(self.REG_CONFIG, config) def _check_int_range(self, value, value_min, value_max): """Check the type and bounds check an expected int value.""" if type(value) is not int: raise TypeError("Value should be an integer") if value < value_min or value > value_max: raise ValueError( "Value {value} should be between {min} and {max}".format( value=value, min=value_min, max=value_max)) def _check_range(self, value, value_min, value_max): """Check the type and bounds check an expected int value.""" if value < value_min or value > value_max: raise ValueError( "Value {value} should be between {min} and {max}".format( value=value, min=value_min, max=value_max)) def _servo_us_to_degrees(self, us, us_min, us_max): """Converts pulse time in microseconds to degrees :param us: Pulse time in microseconds :param us_min: Minimum possible pulse time in microseconds :param us_max: Maximum possible pulse time in microseconds """ self._check_range(us, us_min, us_max) servo_range = us_max - us_min angle = (float(us - us_min) / float(servo_range)) * 180.0 return int(round(angle, 0)) - 90 def _servo_degrees_to_us(self, angle, us_min, us_max): """Converts degrees into a servo pulse time in microseconds :param angle: Angle in degrees from -90 to 90 """ self._check_range(angle, -90, 90) angle += 90 servo_range = us_max - us_min us = (servo_range / 180.0) * angle return us_min + int(us) def _servo_range(self, servo_index): """Get the min and max range values for a servo""" return (self._servo_min[servo_index], self._servo_max[servo_index]) def _i2c_write_block(self, reg, data): if type(data) is list: for x in range(self._i2c_retries): try: self._i2c.write_i2c_block_data(self._i2c_address, reg, data) return except IOError: time.sleep(self._i2c_retry_time) continue raise IOError("Failed to write block") else: raise ValueError("Value must be a list") def _i2c_write_word(self, reg, data): if type(data) is int: for x in range(self._i2c_retries): try: self._i2c.write_word_data(self._i2c_address, reg, data) return except IOError: time.sleep(self._i2c_retry_time) continue raise IOError("Failed to write word") def _i2c_write_byte(self, reg, data): if type(data) is int: for x in range(self._i2c_retries): try: self._i2c.write_byte_data(self._i2c_address, reg, data) return except IOError: time.sleep(self._i2c_retry_time) continue raise IOError("Failed to write byte") def _i2c_read_byte(self, reg): for x in range(self._i2c_retries): try: return self._i2c.read_byte_data(self._i2c_address, reg) except IOError: time.sleep(self._i2c_retry_time) continue raise IOError("Failed to read byte") def _i2c_read_word(self, reg): for x in range(self._i2c_retries): try: return self._i2c.read_word_data(self._i2c_address, reg) except IOError: time.sleep(self._i2c_retry_time) continue raise IOError("Failed to read byte") def clear(self): """Clear the buffer.""" self._pixels = [0] * self.NUM_LEDS * 3 self._pixels += [1] def light_mode(self, mode): """Set the light mode for attached lights. PanTiltHAT can drive either WS2812 or SK6812 pixels, or provide a PWM dimming signal for regular LEDs. * PWM - PWM-dimmable LEDs * WS2812 - 24 WS2812 or 18 SK6812 pixels """ self.setup() self._light_mode = mode self._set_config() def light_type(self, set_type): """Set the light type for attached lights. Set the type of lighting strip connected: * RGB - WS2812 pixels with RGB pixel order * RGB - WS2812 pixels with GRB pixel order * RGBW - SK6812 pixels with RGBW pixel order * GRBW - SK6812 pixels with GRBW pixel order """ self._light_type = set_type def num_pixels(self): """Returns the supported number of pixels depending on light mode. RGBW or GRBW support 18 pixels RGB supports 24 pixels """ if self._light_type in [RGBW, GRBW]: return 18 return 24 def brightness(self, brightness): """Set the brightness of the connected LED ring. This only applies if light_mode has been set to PWM. It will be ignored otherwise. :param brightness: Brightness from 0 to 255 """ self.setup() self._check_int_range(brightness, 0, 255) if self._light_mode == PWM: # The brightness value is taken from the first register of the WS2812 chain self._i2c_write_byte(self.REG_WS2812, brightness) def set_all(self, red, green, blue, white=None): """Set all pixels in the buffer. :param red: Amount of red, from 0 to 255 :param green: Amount of green, from 0 to 255 :param blue: Amount of blue, from 0 to 255 :param white: Optional amount of white for RGBW and GRBW strips """ for index in range(self.num_pixels()): self.set_pixel(index, red, green, blue, white) def set_pixel_rgbw(self, index, red, green, blue, white): """Set a single pixel in the buffer for GRBW lighting stick :param index: Index of pixel from 0 to 17 :param red: Amount of red, from 0 to 255 :param green: Amount of green, from 0 to 255 :param blue: Amount of blue, from 0 to 255 :param white: Amount of white, from 0 to 255 """ self.set_pixel(index, red, green, blue, white) def set_pixel(self, index, red, green, blue, white=None): """Set a single pixel in the buffer. :param index: Index of pixel from 0 to 23 :param red: Amount of red, from 0 to 255 :param green: Amount of green, from 0 to 255 :param blue: Amount of blue, from 0 to 255 :param white: Optional amount of white for RGBW and GRBW strips """ self._check_int_range(index, 0, self.num_pixels() - 1) for color in [red, green, blue]: self._check_int_range(color, 0, 255) if white is not None: self._check_int_range(white, 0, 255) if self._light_type in [RGBW, GRBW]: index *= 4 if self._light_type == RGBW: self._pixels[index] = red self._pixels[index + 1] = green self._pixels[index + 2] = blue if self._light_type == GRBW: self._pixels[index] = green self._pixels[index + 1] = red self._pixels[index + 2] = blue if white is not None: self._pixels[index + 3] = white else: index *= 3 if self._light_type == RGB: self._pixels[index] = red self._pixels[index + 1] = green self._pixels[index + 2] = blue if self._light_type == GRB: self._pixels[index] = green self._pixels[index + 1] = red self._pixels[index + 2] = blue def show(self): """Display the buffer on the connected WS2812 strip.""" self.setup() self._i2c_write_block(self.REG_WS2812, self._pixels[:32]) self._i2c_write_block(self.REG_WS2812 + 32, self._pixels[32:64]) self._i2c_write_block(self.REG_WS2812 + 64, self._pixels[64:]) self._i2c_write_byte(self.REG_UPDATE, 1) def servo_enable(self, index, state): """Enable or disable a servo. Disabling a servo turns off the drive signal. It's good practise to do this if you don't want the Pan/Tilt to point in a certain direction and instead want to save power. :param index: Servo index: either 1 or 2 :param state: Servo state: True = on, False = off """ self.setup() if index not in [1, 2]: raise ValueError("Servo index must be 1 or 2") if state not in [True, False]: raise ValueError("State must be True/False") if index == 1: self._enable_servo1 = state else: self._enable_servo2 = state self._set_config() def servo_pulse_min(self, index, value): """Set the minimum high pulse for a servo in microseconds. :param value: Value in microseconds """ if index not in [1, 2]: raise ValueError("Servo index must be 1 or 2") self._servo_min[index - 1] = value def servo_pulse_max(self, index, value): """Set the maximum high pulse for a servo in microseconds. :param value: Value in microseconds """ if index not in [1, 2]: raise ValueError("Servo index must be 1 or 2") self._servo_max[index - 1] = value def get_servo_one(self): """Get position of servo 1 in degrees.""" self.setup() us_min, us_max = self._servo_range(0) us = self._i2c_read_word(self.REG_SERVO1) return self._servo_us_to_degrees(us, us_min, us_max) def get_servo_two(self): """Get position of servo 2 in degrees.""" self.setup() us_min, us_max = self._servo_range(1) us = self._i2c_read_word(self.REG_SERVO2) return self._servo_us_to_degrees(us, us_min, us_max) def servo_one(self, angle): """Set position of servo 1 in degrees. :param angle: Angle in degrees from -90 to 90 """ self.setup() if not self._enable_servo1: self._enable_servo1 = True self._set_config() us_min, us_max = self._servo_range(0) us = self._servo_degrees_to_us(angle, us_min, us_max) self._i2c_write_word(self.REG_SERVO1, us) if self._idle_timeout > 0: if self._servo1_timeout is not None: self._servo1_timeout.cancel() self._servo1_timeout = Timer(self._idle_timeout, self._servo1_stop) self._servo1_timeout.daemon = True self._servo1_timeout.start() def _servo1_stop(self): self._servo1_timeout = None self._enable_servo1 = False self._set_config() def servo_two(self, angle): """Set position of servo 2 in degrees. :param angle: Angle in degrees from -90 to 90 """ self.setup() if not self._enable_servo2: self._enable_servo2 = True self._set_config() us_min, us_max = self._servo_range(1) us = self._servo_degrees_to_us(angle, us_min, us_max) self._i2c_write_word(self.REG_SERVO2, us) if self._idle_timeout > 0: if self._servo2_timeout is not None: self._servo2_timeout.cancel() self._servo2_timeout = Timer(self._idle_timeout, self._servo2_stop) self._servo2_timeout.daemon = True self._servo2_timeout.start() def _servo2_stop(self): self._servo2_timeout = None self._enable_servo2 = False self._set_config() pan = servo_one tilt = servo_two get_pan = get_servo_one get_tilt = get_servo_two
p.ChangeFrequency(note[0]) sleep(note[1]) p.stop() p.ChangeFrequency(N_BOUNCE) for led in LEDS: gpio.setup(led, gpio.OUT) oldBugger = WIDTH * HEIGHT * [None] oldTime = time() counter = 0 sorry = True while 1: newTime = time() counter += newTime - oldTime if newTime - sfxStartTime > sfxLength: p.stop() adc.write_byte(33, 128) knob = adc.read_word_data(33, 0) knob = ((knob & 15) << 8 | knob >> 8) - 683 if knob < 0: knob = 0 elif knob > 2730: knob = 2730 Player0Bat = HEIGHT - int(round(knob * (HEIGHT - Player0Height) / 2731.)) - Player0Height if sorry: knob = adc.read_byte_data(36,0) - 9 if knob < 0: knob = 0 elif knob > 220: knob = 220 Player1Bat = HEIGHT - int(round(knob * (HEIGHT - Player1Height) / 220.)) - Player1Height gpio.output(17, 1) gpio.output(17, 0) sorry = not sorry if Player0SizeCounter < 15: Player0SizeCounter += newTime - oldTime else: Player0Height = 3 if Player1SizeCounter < 15: Player1SizeCounter += newTime - oldTime
class SHT21 : RHmeasure_noHold = 0xF5 Tmeasure_noHold = 0xF3 RHmeasure_Hold = 0xE5 Tmeasure_Hold = 0xE3 Soft_Reset = 0xFE Write_Reg = 0xE6 Read_Reg = 0xE7 ############################################################################## ## Experimental register found by looking for each one individually ## ## with a 10 seconds wait between each try. CheckCRC says true for all. ## RH_Reg = 0x05 ## T_Reg = 0x03 ## ## read_reg? 0x06 ## ## read_reg 0x07 ## ## unknown 0x09 result was 6,0,90(constant over time) ## ## unknown 0x0F result was 2,68,32(constant over time) ## ## serial number? 0x1A periodic on 64 bits? ## ## result was [25, 203, 218, 223, 71, 170, 137, 242, 217, 140, 232 ## ## , 120, 231, 86, 128, 122, 7, 151, 248, 59, 252, 255, ## ## 232, 120, 54, 99, 129, 75, 30, 92, 80, 126] ## ## serial number? 0x1B same as 0x1A with random shift ## ## T_reg? 0xE3 result was 103,88,60(made a new measure?) ## ## RH_reg? 0xE5 result was 83,206,146(new measure?) ## ## read_reg 0xE6 result was 58,30 ## ## read_reg 0xE7 result was 58,30 ## ## unknown 0xE9 result was 6,0,90 ## ## unknown 0xEF result was 2,68,32 ## ## serial number 0xFA same as 1A, check sensirion(says 64 bits ID)## ## serial number? 0xFB same as 1B ## ## device ID? 0xFF check i2c full specs, results seems random ## ############################1################################################# class CRCError(Exception): pass def __init__(self, addr, busnum = 1) : self.address = addr self.bus = SMBus(busnum) #self.bus.open(busnum) self.Reset() #reg = self.ReadReg() reg = 0 if (reg & 0x80) and (reg & 0x01): self.RH_res = 11 self.T_res = 11 elif (reg & 0x80) and not(reg & 0x01): self.RH_res = 10 self.T_res = 13 elif not(reg & 0x80) and not(reg & 0x01): self.RH_res = 12 self.T_res = 14 else: self.RH_res = 8 self.T_res = 12 def getRH(self): self.bus.write_byte(self.address, self.RHmeasure_noHold) time.sleep(0.1) RH = self.bus.read_i2c_block_data(self.address, self.RH_Reg, 3) #print RH if self.CheckCRC(RH): self.RHum = RH RH[1] &= ~0x03 #reset 2 status bits(LSB) return -6+125.*(RH[0]*256+RH[1])/65536. else: #print 'CRC checksum failed, data was corrupted(RH reading)' #return -1 raise self.CRCError def getT(self): self.bus.write_byte(self.address, self.Tmeasure_noHold) time.sleep(0.1) T = self.bus.read_i2c_block_data(self.address, self.T_Reg, 3) #print T if self.CheckCRC(T): self.Temp = T T[1] &= ~0x03 #reset 2 status bits(LSB) return -46.85+175.72*(T[0]*256+T[1])/65536. else: #print 'CRC checksum failed, data was corrupted(temp reading)' #return -1 raise self.CRCError def Reset(self): self.bus.write_byte(self.address, self.Soft_Reset) time.sleep(0.02) #must wait 15ms def ReadReg(self): reg = self.bus.read_word_data(self.address, self.Read_Reg) crc = [ reg & 0xFF, (reg & 0xFF00) >> 8] if self.CheckCRC(crc): return reg & 0xFF else: #print 'Error : CRC not matching !' #return 0 raise self.CRCError def WriteReg(self, val): reg = self.ReadReg() reg &= 0x38 self.bus.write_byte_data(self.address, self.Write_Reg, val) def test(self): self.T = [] self.getRH() self.getT() for i in range(256): try : time.sleep(10) self.T.append((hex(i), self.bus.read_i2c_block_data(sensor.address, i))) print(hex(i), 'success reading') except IOError as err: print(hex(i), 'failed reading') return self.T def CheckCRC(self, buf): poly = 0x131 crc = 0 #print buf[2] for by in buf: crc ^= by for i in range(8): if crc & 0x80 : crc = (crc << 1)^poly else: crc <<= 1 #print crc return crc==0
def getCurrent(self): bus = SMBus(1) self.current = self.decodePMBus(bus.read_word_data(self.address, 0x8C)) bus.close() return self.current
def getVoltageOut(self): bus = SMBus(1) voltageOutMessage = bus.read_word_data(self.address, 0x8B) bus.close() self.voltageOut = voltageOutMessage * (2.0**self.VOUT_N) return self.voltageOut
def getVoltageIn(self): bus = SMBus(1) self.voltageIn = self.decodePMBus( bus.read_word_data(self.address, 0x88)) bus.close() return self.voltageIn
class SRF02: def __init__(self): self._i2c = SMBus(1) self._i2c_address = SRF02_I2C_ADDRESS self._waiting_for_echo = False yesterday = datetime.now() - timedelta(1) self._time_last_burst = yesterday # The last distance measurement self.distance = None # meters # On power up, the detection threshold is set to 28cm (11") self.mindistance = 0.28 # meters # This is mostly for debugging and testing self.num_bursts_sent = 0 # check that the sensor is present - read the version self.version = self._read_version() log.info("SRF-02 Ultrasonic Sensor initialized. Version: %d" % self.version) # we want to check how often we get exceptions self.error_counter = 0 # Should be called in some sensor loop, maybe at 100Hz. Is fast. # Will trigger an ultrasonic burst or check if we received an echo. # I we have a measurement, it is returned in meters. def update(self): distance = None now = datetime.now() time_since_last_burst = (now - self._time_last_burst).total_seconds() # log.debug("time since last burst: {}".format(time_since_last_burst)) if self._waiting_for_echo: # make sure we wait at least some amount of time before we read if time_since_last_burst > SRF02_MIN_TIME_BETWEEN_BURST_READ: # check if we have an echo distance = self._read_echo() # Fallback if we don't get an echo, just stop waiting # from the data sheet: # The SRF02 will always be ready 70mS after initiating the ranging. if distance is None and time_since_last_burst > SRF02_MAX_WAIT_TIME: log.warn("Fallback! Waited longer than 70ms!") self._waiting_for_echo = False if (not self._waiting_for_echo) and time_since_last_burst > SRF02_MIN_TIME_BETWEEN_BURSTS: self._send_burst() expected_error = self._calc_expected_error(distance) return distance, expected_error def _send_burst(self): self._i2c.write_byte_data(self._i2c_address, 0, 0x51) self._waiting_for_echo = True self._time_last_burst = datetime.now() self.num_bursts_sent += 1 log.debug("Burst sent.") def _read_echo(self): # it must be possible to read all of these data in 1 i2c transaction # buf[0] software version. If this is 255, then the ping has not yet returned # buf[1] unused # buf[2] high byte range # buf[3] low byte range # buf[4] high byte minimum auto tuned range # buf[5] low byte minimum auto tuned range # We use the version information to detect if the result is there yet. # 255 is a dummy version for the case that no echo has been received yet. For me, the real version is "6". if self._read_version() == 255: log.debug("Version is 255") return None self.distance = self._i2c.read_word_data(self._i2c_address, 2) / 255 / 100 self.mindistance = self._i2c.read_word_data(self._i2c_address, 4) / 255 / 100 # A value of 0 indicates that no objects were detected. We prefer None to represent this. if self.distance == 0: self.distance = None self._waiting_for_echo = False log.debug("echo received! distance is: {}".format(self.distance)) return self.distance # The version can be read from register 0. # Reading it has no real value for us, but we can use it to determine if a measurement is finished or not. def _read_version(self): try: return self._i2c.read_byte_data(self._i2c_address, 0) # 255 means that the unit is still measuring the distance except IOError: log.error("Recovering from IOError") self.error_counter += 1 return 255 # find out what kind of error we expect (used in sensor fusion) def _calc_expected_error(self, distance): # no reading at all if distance is None: return SENSOR_ERROR_MAX # object too close if distance <= self.mindistance: return SRF02_SENSOR_ERROR_LOW_RANGE # good distance, nice measurement elif distance <= SRF02_MAX_RANGE: return SRF02_SENSOR_ERROR_GOOD_RANGE # object too far else: return SRF02_SENSOR_ERROR_HIGH_RANGE
from smbus import SMBus from time import sleep x = 1 while True: try: i2cbus = SMBus(1) i2cbus.write_byte(0x70, 0x51) sleep(0.12) val = i2cbus.read_word_data(0x70, 0xe1) print (val >> 8) & 0xff | (val>>8 & 0xff), 'cm'
from smbus import SMBus from time import sleep i2c = SMBus(1) while True: try: i2c.write_byte(0x70, 0x51) sleep(0.3) datin = i2c.read_word_data(0x70, 0xe1) print ((datin >> 8) & 0x00ff) | ((datin << 8) & 0xff00), 'cm' except: print err
class weather(): _cal_AC1 = 0 _cal_AC2 = 0 _cal_AC3 = 0 _cal_AC4 = 0 _cal_AC5 = 0 _cal_AC6 = 0 _cal_B1 = 0 _cal_B2 = 0 _cal_MB = 0 _cal_MC = 0 _cal_MD = 0 bmp180 = 0 bh1750 = 0 lm75addr = 0 i2c1 = 0 db = 0 api = 0 feed = 0 tempds = 0 lightds = 0 pressds = 0 def __init__(self): self.lm75addr = 0x4f self.bmp180 = 0x77 self.bh1750 = 0x23 self.i2c1 = SMBus(1) self.calibration() def calibration(self): self._cal_AC1 = self.read_16bit_regs(self.bmp180, 0xaa) self._cal_AC2 = self.read_16bit_regs(self.bmp180, 0xac) self._cal_AC3 = self.read_16bit_regs(self.bmp180, 0xae) self._cal_AC4 = self.read_16bit_regu(self.bmp180, 0xb0) self._cal_AC5 = self.read_16bit_regu(self.bmp180, 0xb2) self._cal_AC6 = self.read_16bit_regu(self.bmp180, 0xb4) self._cal_B1 = self.read_16bit_regs(self.bmp180, 0xb6) self._cal_B2 = self.read_16bit_regs(self.bmp180, 0xb8) self._cal_MB = self.read_16bit_regs(self.bmp180, 0xba) self._cal_MC = self.read_16bit_regs(self.bmp180, 0xbc) self._cal_MD = self.read_16bit_regs(self.bmp180, 0xbe) def readRawTemp(self): self.i2c1.write_byte_data(self.bmp180, 0xf4, 0x2e) time.sleep(0.005) raw = self.read_16bit_regu(self.bmp180, 0xf6) return raw def readTemperature(self): ut = self.readRawTemp() x1 = ((ut - self._cal_AC6) * self._cal_AC5) >> 15 x2 = (self._cal_MC << 11) / (x1 + self._cal_MD) b5 = x1 + x2 temp = ((b5 + 8) >> 4)/10.0 return temp def readRawPressure(self): self.i2c1.write_byte_data(self.bmp180, 0xf4, 0xf4) #Read ultra high resolution time.sleep(0.026) msb = self.i2c1.read_byte_data(self.bmp180, 0xf6) lsb = self.i2c1.read_byte_data(self.bmp180, 0xf7) xlsb = self.i2c1.read_byte_data(self.bmp180, 0xf8) raw = (msb << 16) + (lsb << 8) + (xlsb) >> 5 return raw def readPressure(self): # Get raw temperature and pressure ut = self.readRawTemp() up = self.readRawPressure() # Convert to actual compensated and calibrated pressure (see Datasheet) x1 = ((ut - self._cal_AC6) * self._cal_AC5) >> 15 x2 = (self._cal_MC << 11) / (x1 + self._cal_MD) b5 = x1 + x2 b6 = b5 - 4000 x1 = (self._cal_B2 * (b6 * b6) >> 12) >> 11 x2 = (self._cal_AC2 * b6) >> 11 x3 = x1 + x2 b3 = (((self._cal_AC1 * 4 + x3) << 3) + 2) / 4 x1 = (self._cal_AC3 * b6) >> 13 x2 = (self._cal_B1 * ((b6 * b6) >> 12)) >> 16 x3 = ((x1 + x2) + 2) >> 2 b4 = (self._cal_AC4 * (x3 + 32768)) >> 15 b7 = (up - b3) * (50000 >> 3) if (b7 < 0x80000000): p = (b7 * 2) / b4 else: p = (b7 / b4) * 2 x1 = (p >> 8) * (p >> 8) x1 = (x1 * 3038) >> 16 x2 = (-7357 * p) >> 16 p = p + ((x1 + x2 + 3791) >> 4) return p def readLM75Temperature(self): # Measure temperature temp = self.i2c1.read_word_data(self.lm75addr,0) # Swap lower and higher byte temp = (((temp & 0xff) << 8)|((temp >> 8) & 0xff)) value = temp >> 5 # Make signed integer if (temp & 0x8000): # one's complement value = (~value & 0x1FF) # two's complement value = value - 1 # significance: means negative temp value = -value value = value / 8.0 return value def readBH1750Light(self): # Measure light luxtmp = self.i2c1.read_word_data(self.bh1750, 0x10) # Convert to actual lux (see Datasheet) lux = (((luxtmp >> 8) & 0xff) | ((luxtmp & 0xff) << 8))/1.2 return lux def measure(self): thisdate = datetime.datetime.utcnow() temperature = self.readLM75Temperature() lux = self.readBH1750Light() pressure = float(self.readPressure()/100) return {'time':str(thisdate), 'temp':round(temperature,2), 'light':round(lux,2), 'pressure':round(float(pressure),2)} def print_climate(self): print "The temperature is: %i Degrees Celsius" % (self.readLM75Temperature()) print "The light intensity is: %i Lux" % (self.readBH1750Light()) print "The pressure is: %i Pascal" % (self.readPressure()) def read_16bit_regu(self, address, register): a = self.i2c1.read_byte_data(address, register) b = self.i2c1.read_byte_data(address, register+1) return ((a << 8) | b) def read_16bit_regs(self, address, register): a = self.i2c1.read_byte_data(address, register) b = self.i2c1.read_byte_data(address, register+1) c = (a << 8)|b if (c & 0x8000): c = (~c & 0xffff) c = c-1 c = -c return c
def sigint_handle(signal_recieved, frame): running = False signal(SIGINT, sigint_handle) # Create I2C bus bus = SMBus(1) INIT_SIGNAL = 0x01 #init signal fori2c while (running): # NOTE: May need to move [D040] <= 0x06 inside the loop here, but I don't think you do sleep(SENSOR_MEASUREMENT_WAIT_TIME) # Tell the sensor we want to read the flow value [D051/D052] => Read Compensated Flow value answer = bus.read_word_data(PRESSURE_SENSOR_ADDRESS, INIT_SIGNAL) #bit shift to get the full value answer = float((((answer & 0x00FF) << 8) + ((answer & 0xFF00) >> 8))) pressure = (answer - SENSOR_COUNT_MIN) * ( SENSOR_PRESSURE_MAX - SENSOR_PRESSURE_MIN) / ( SENSOR_COUNT_MAX - SENSOR_COUNT_MIN) + SENSOR_PRESSURE_MIN # Output for the user print(f"Sensor Reading {pressure:.3f} psi" + " " * 20, end='\r') print("Exiting program...") bus.close()
class SHT21: RHmeasure_noHold = 0xF5 Tmeasure_noHold = 0xF3 RHmeasure_Hold = 0xE5 Tmeasure_Hold = 0xE3 Soft_Reset = 0xFE Write_Reg = 0xE6 Read_Reg = 0xE7 ############################################################################## ## Experimental register found by looking for each one individually ## ## with a 10 seconds wait between each try. CheckCRC says true for all. ## RH_Reg = 0x05 ## T_Reg = 0x03 ## ## read_reg? 0x06 ## ## read_reg 0x07 ## ## unknown 0x09 result was 6,0,90(constant over time) ## ## unknown 0x0F result was 2,68,32(constant over time) ## ## serial number? 0x1A periodic on 64 bits? ## ## result was [25, 203, 218, 223, 71, 170, 137, 242, 217, 140, 232 ## ## , 120, 231, 86, 128, 122, 7, 151, 248, 59, 252, 255, ## ## 232, 120, 54, 99, 129, 75, 30, 92, 80, 126] ## ## serial number? 0x1B same as 0x1A with random shift ## ## T_reg? 0xE3 result was 103,88,60(made a new measure?) ## ## RH_reg? 0xE5 result was 83,206,146(new measure?) ## ## read_reg 0xE6 result was 58,30 ## ## read_reg 0xE7 result was 58,30 ## ## unknown 0xE9 result was 6,0,90 ## ## unknown 0xEF result was 2,68,32 ## ## serial number 0xFA same as 1A, check sensirion(says 64 bits ID)## ## serial number? 0xFB same as 1B ## ## device ID? 0xFF check i2c full specs, results seems random ## ############################1################################################# class CRCError(Exception): pass def __init__(self, addr, busnum=1): self.address = addr self.bus = SMBus(busnum) #self.bus.open(busnum) self.Reset() #reg = self.ReadReg() reg = 0 if (reg & 0x80) and (reg & 0x01): self.RH_res = 11 self.T_res = 11 elif (reg & 0x80) and not (reg & 0x01): self.RH_res = 10 self.T_res = 13 elif not (reg & 0x80) and not (reg & 0x01): self.RH_res = 12 self.T_res = 14 else: self.RH_res = 8 self.T_res = 12 def getRH(self): self.bus.write_byte(self.address, self.RHmeasure_noHold) time.sleep(0.1) RH = self.bus.read_i2c_block_data(self.address, self.RH_Reg, 3) #print RH if self.CheckCRC(RH): self.RHum = RH RH[1] &= ~0x03 #reset 2 status bits(LSB) return -6 + 125. * (RH[0] * 256 + RH[1]) / 65536. else: #print 'CRC checksum failed, data was corrupted(RH reading)' #return -1 raise self.CRCError def getT(self): self.bus.write_byte(self.address, self.Tmeasure_noHold) time.sleep(0.1) T = self.bus.read_i2c_block_data(self.address, self.T_Reg, 3) #print T if self.CheckCRC(T): self.Temp = T T[1] &= ~0x03 #reset 2 status bits(LSB) return -46.85 + 175.72 * (T[0] * 256 + T[1]) / 65536. else: #print 'CRC checksum failed, data was corrupted(temp reading)' #return -1 raise self.CRCError def Reset(self): self.bus.write_byte(self.address, self.Soft_Reset) time.sleep(0.02) #must wait 15ms def ReadReg(self): reg = self.bus.read_word_data(self.address, self.Read_Reg) crc = [reg & 0xFF, (reg & 0xFF00) >> 8] if self.CheckCRC(crc): return reg & 0xFF else: #print 'Error : CRC not matching !' #return 0 raise self.CRCError def WriteReg(self, val): reg = self.ReadReg() reg &= 0x38 self.bus.write_byte_data(self.address, self.Write_Reg, val) def test(self): self.T = [] self.getRH() self.getT() for i in range(256): try: time.sleep(10) self.T.append( (hex(i), self.bus.read_i2c_block_data(sensor.address, i))) print(hex(i), 'success reading') except IOError as err: print(hex(i), 'failed reading') return self.T def CheckCRC(self, buf): poly = 0x131 crc = 0 #print buf[2] for by in buf: crc ^= by for i in range(8): if crc & 0x80: crc = (crc << 1) ^ poly else: crc <<= 1 #print crc return crc == 0
def parse(t): # 9 bits of resolution stored in 2 bytes r = t >> 7 # MSB set? if t & 0x8000: # one's complement r = ~r & 0x1FF # two's complement r = r - 1 # significance: means negative temp r = -r r = r / 2.0 return r def ctof(t): return ((9.0 / 5.0) * parse(t)) + 32.0 while True: temp = i2c1.read_word_data(addr, 0) tempA = temp & 0xFF tempB = (temp >> 8) & 0xFF temp = (tempA << 8) | tempB print "read: %04x = %.1f C (%.1f F)" % (temp, parse(temp), ctof(temp)) time.sleep(0.5)
class Device(object): """Class for communicating with an I2C device using the smbus library. Allows reading and writing 8-bit, 16-bit, and byte array values to registers on the device.""" def __init__(self, address, busnum): """Create an instance of the I2C device at the specified address on the specified I2C bus number.""" self._address = address self._bus = SMBus(busnum) def writeRaw8(self, value): """Write an 8-bit value on the bus (without register).""" value = value & 0xFF self._bus.write_byte(self._address, value) def write8(self, register, value): """Write an 8-bit value to the specified register.""" value = value & 0xFF self._bus.write_byte_data(self._address, register, value) def write16(self, register, value): """Write a 16-bit value to the specified register.""" value = value & 0xFFFF self._bus.write_word_data(self._address, register, value) def writeList(self, register, data): """Write bytes to the specified register.""" self._bus.write_i2c_block_data(self._address, register, data) def readList(self, register, length): """Read a length number of bytes from the specified register. Results will be returned as a bytearray.""" results = self._bus.read_i2c_block_data(self._address, register, length) return results def readRaw8(self): """Read an 8-bit value on the bus (without register).""" result = self._bus.read_byte(self._address) & 0xFF return result def readU8(self, register): """Read an unsigned byte from the specified register.""" result = self._bus.read_byte_data(self._address, register) & 0xFF return result def readS8(self, register): """Read a signed byte from the specified register.""" result = self.readU8(register) if result > 127: result -= 256 return result def readU16(self, register, little_endian=True): """Read an unsigned 16-bit value from the specified register, with the specified endianness (default little endian, or least significant byte first).""" result = self._bus.read_word_data(self._address, register) & 0xFFFF # Swap bytes if using big endian because read_word_data assumes little # endian on ARM (little endian) systems. if not little_endian: result = ((result << 8) & 0xFF00) + (result >> 8) return result def readS16(self, register, little_endian=True): """Read a signed 16-bit value from the specified register, with the specified endianness (default little endian, or least significant byte first).""" result = self.readU16(register, little_endian) if result > 32767: result -= 65536 return result def readU16LE(self, register): """Read an unsigned 16-bit value from the specified register, in little endian byte order.""" return self.readU16(register, little_endian=True) def readU16BE(self, register): """Read an unsigned 16-bit value from the specified register, in big endian byte order.""" return self.readU16(register, little_endian=False) def readS16LE(self, register): """Read a signed 16-bit value from the specified register, in little endian byte order.""" return self.readS16(register, little_endian=True) def readS16BE(self, register): """Read a signed 16-bit value from the specified register, in big endian byte order.""" return self.readS16(register, little_endian=False)
class MLX90614_IR_sensor(): '''This class will read the IR temperatue values from the sensor''' def __init__(self, address): '''Initalizing all variables ''' #address working at self.address = address #note that the default slave address is 0x00 #TODO: how to detect several different addresses at once #self.address = 0x5a #Objec temperature address self.tobj_address = 0x27 #0x27 #ambien temperature address self.tamb_address = 0x26 #0x26 #smbus command setup self.bus = SMBus(1) #inital ambient and object temperatures self.init_tamb_value = 0.0 self.init_tobj_value = 0.0 #inital tamb and tobj values converted to Celsius self.tamb_ans = 0.0 self.tobj_ans = 0.0 #ambient temperature self.tamb_num = 0.0 #object temperature self.tobj_num = 0.0 self.tobj_percent_limit_up = 0.0 self.tobj_percent_limit_down = 0.0 self.tamb_percent_limit_up = 0.0 self.tamb_percent_limit_down = 0.0 #instantiate the config file and extract the dict #opening the config file self.config = config.config.Config() #reading the config file #self.config.readconfig() #extract the slice and slice values #print self.config.dict #dict length for data analysis self.length = int(self.config.dict['length']) #slice length of data analysis self.slice = int(self.config.dict['slice']) #importing the control_variable() class to obtain the jump and limit values self.control_class = mlx.control_variable.Control_Variable() self.control_class.run() self.tobj_jump_value = 0.0 self.tamb_jump_value = 0.0 self.cycle = 0 self.counter = 0 self.tamb_data_analysis_list = [] self.tobj_data_analysis_list = [] self.tobj_data_analysis_result = [] self.tamb_data_analysis_result = [] #this is the record_list which is the varible passed to the gui #note that we are initalizing all variables with 0 are the six variables are there #the appended list data is being stored to the log files, the gui will only show a subaspect of the data self.record_list = [0, 0, 0, 0, 0, 0] self.record_dict = {self.address: []} #, 'cycle':self.cycle } def read(self): '''getting the values from the IR device sensor''' self.init_tobj_value = self.bus.read_word_data(self.address, self.tobj_address) #sleep for 200 ms the time for the sensor is at least 144 ms time.sleep(0.2) self.init_tamb_value = self.bus.read_word_data(self.address, self.tamb_address) #sleep for 200 ms the timer for the sensor is at least 144 ms time.sleep(0.2) def object_temp_analysis(self): '''this function converts the object temperature from kelvin to celsius values''' #converting values from long bits into degrees celsius #using fomula in sensor datasheet manual #pg ????? #convert temperatures from kelvin to celsius tobj_ans = (self.init_tobj_value * 0.02) - 273.15 #print tobj_ans self.tobj_ans = tobj_ans #mylog2.debug('Tobj: ' + repr(tobj_ans) ) #calculate jump value jump_value = tobj_ans - self.tobj_num #- tobj_ans #save calculated jump value to self value self.tobj_jump_value = jump_value #print 'obj jump: ', jump_value mylog2.debug('obj jump value: ' + repr(jump_value)) #comparing jump value to control jump value set by user if jump_value >= self.control_class.jump_value: #reinitalize variables self.tobj_num = tobj_ans #calculate percent limit self.tobj_percent_limit_up = self.tobj_num * self.control_class.limit_value print '*****TOBJ UP*****' mylog2.debug('UP VALUE-Tobj:--> ' + 'object temperature value: ' + repr(self.tobj_num) + 'jump up value: ' + repr(jump_value) + 'temp limit value: ' + repr(self.tobj_percent_limit_up) + 'jump value: ' + repr(self.control_class.jump_value)) elif jump_value <= -(self.control_class.jump_value): #reinitalize variables self.tobj_num = tobj_ans #calculating percent limit self.tobj_percent_limit_down = self.tobj_num * self.control_class.limit_value print '******TOBJ DOWN*****' mylog2.debug('DOWN VALUE-Tobj:--> ' + 'object temperature value: ' + repr(self.tobj_num) + 'jump up value: ' + repr(jump_value) + 'temp limit value: ' + repr(self.tobj_percent_limit_down) + 'jump value: ' + repr(self.control_class.jump_value)) else: print 'no change' def ambient_temp_analysis(self): '''this function records the ambient temperatuer and converts the value to degrees celsisus ''' tamb_ans = (self.init_tamb_value * 0.02) - 273.15 #print tamb_ans #mylog2.debug('tamb ans: ' + repr(tamb_ans) ) self.tamb_ans = tamb_ans #calculate jump value jump_value = tamb_ans - self.tamb_num #- tamb_ans #print 'amb jump: ', jump_value if jump_value >= self.control_class.jump_value: #assuming the value is + #reinitalize varialbes self.tamb_num = tamb_ans #calculate percent limit tamb_percent_limit_up = self.tamb_num * self.control_class.limit_value print '*********TAMB UP***********' mylog2.debug('UP VALUE-Tamb:-->' + 'Ambient temperature value: ' + repr(self.tamb_num) + 'jump up value: ' + repr(jump_value) + 'temp limit value: ' + repr(self.tamb_percent_limit_up) + 'jump value: ' + repr(self.control_class.jump_value)) elif jump_value <= -(self.control_class.jump_value): #reinitalize variables self.tamb_num = tamb_ans #calculate percent limit tamb_percent_limit_down = self.tamb_num * self.control_class.limit_value print '*********TAMB DOWN***********' mylog2.debug('DOWN VALUE-Tamb' + 'Ambient temperature value: ' + repr(self.tamb_num) + 'jump up value: ' + repr(jump_value) + 'temp limit value: ' + repr(self.tamb_percent_limit_down) + 'jump value: ' + repr(self.control_class.jump_value)) else: print 'no change' def data_analysis(self): '''This function does the data analysis for the data ''' #appending items to list self.tobj_data_analysis_list.append(self.tobj_ans) #_num) self.tamb_data_analysis_list.append(self.tamb_ans) #num) if len(self.tobj_data_analysis_list) > self.length: #15: #if the length is greater then 50 for item in self.tobj_data_analysis_list[:self.slice]: #10]: #take out the first 20 items and pop them out self.tobj_data_analysis_list.pop(0) if len(self.tamb_data_analysis_list) > self.length: #15: #pop out the first 20 items in the list for item in self.tamb_data_analysis_list[:self.slice]: #10]: self.tamb_data_analysis_list.pop(0) #doing tobject calculations tobj_min = min(self.tobj_data_analysis_list[-self.slice:]) #[-5:]) tobj_max = max(self.tobj_data_analysis_list[-self.slice:]) #[-5:]) tobj_sum = sum(self.tobj_data_analysis_list[-self.slice:]) #[-5:]) tobj_len = len( self.tobj_data_analysis_list) #[ -self.slice: ] ) #[-5:]) tobj_avg = tobj_sum / tobj_len #doign tambient claculations tamb_min = min(self.tamb_data_analysis_list[-self.slice:]) #[-5:]) tamb_max = max(self.tamb_data_analysis_list[-self.slice:]) #[-5:]) tamb_sum = sum(self.tamb_data_analysis_list[-self.slice:]) #[-5:]) tamb_len = len( self.tamb_data_analysis_list) #[ -self.slice: ] ) #[-5:]) tamb_avg = tamb_sum / tobj_len self.record_list = [ tobj_min, tobj_max, tobj_avg, tamb_min, tamb_max, tamb_avg, tobj_len, tamb_len ] #logging the data mylog2.debug('Record list: ' + repr(self.record_list)) def record_data(self): '''this function saves the data to csv files note that this data is not needed and necessary TODO: Deprecated function ''' myfile = open(FILENAME, 'a') newrow = time.strftime('%H:%M:%S,') newrow += str(self.cycle) + "," newrow += str(self.address) + "," newrow += str(self.tobj_ans) + "," newrow += str(self.tamb_ans) newrow += NEWLINE myfile.write(newrow) myfile.close() def run(self): ''''Function which runs the value''' #runt the control class to ensure the varaibles are set right and can be changed as needed #self.control_class.run() mylog2.debug('control variable values: ' + repr(self.control_class.jump_value) + "--" + repr(self.control_class.limit_value)) self.cycle += 1 print print 'Time: ', time.strftime('%H:%M:%S,') print 'cycle: ', self.cycle self.read() self.object_temp_analysis() self.ambient_temp_analysis() self.data_analysis() self.record_data() print 'Address: %s -- tobject: %s -- tambient: %s' % ( self.address, self.tobj_num, self.tamb_num) #log the results mylog2.debug('tamb data analysis: ' + repr(self.tamb_data_analysis_result))
class PiPuckMotorServer(object): """ROS Node to expose topics relating to the Pi-puck motors.""" def __init__(self): """Initialise node.""" self._bus = SMBus(I2C_CHANNEL) rospy.on_shutdown(self.close_bus) self._steps_right_pub = rospy.Publisher('motors/steps_right', UInt16, queue_size=10) self._steps_left_pub = rospy.Publisher('motors/steps_left', UInt16, queue_size=10) self._real_steps_right_pub = rospy.Publisher('motors/real_steps_right', Int64, queue_size=10) self._real_steps_left_pub = rospy.Publisher('motors/real_steps_left', Int64, queue_size=10) self._odometry_pub = rospy.Publisher('motors/odometry', Odometry, queue_size=10) rospy.init_node("motors") rospy.Subscriber("motors/speed_right", Float32, self.callback_right) rospy.Subscriber("motors/speed_left", Float32, self.callback_left) self._rate = rospy.Rate(rospy.get_param('~rate', 10)) tf_prefix_key = rospy.search_param("tf_prefix") if tf_prefix_key: tf_prefix = rospy.get_param(tf_prefix_key, None) else: tf_prefix = None if tf_prefix is not None and not tf_prefix.endswith("/"): tf_prefix += "/" self._reference_frame = REFERENCE_FRAME_ID if tf_prefix: self._reference_frame = tf_prefix + self._reference_frame self._left_overflows = 0 self._right_overflows = 0 self._left_steps_previous = 0 self._right_steps_previous = 0 self._real_left_steps_previous = 0 self._real_right_steps_previous = 0 self._left_motor_speed = 0 self._right_motor_speed = 0 self._estimate_x = 0 self._estimate_y = 0 self._estimate_theta = 0 self._last_measurement_time = rospy.get_time() @staticmethod def convert_speed(speed): """Convert input speed data into a speed value for the stepper motors.""" speed = float(speed) if speed > 1.0: speed = 1.0 elif speed < -1.0: speed = -1.0 return int(speed * MAX_SPEED) def callback_left(self, data): """Handle requests for speed change of left motor.""" self._left_motor_speed = data.data self._bus.write_word_data( EPUCK_I2C_ADDR, LEFT_MOTOR_SPEED, PiPuckMotorServer.convert_speed(self._left_motor_speed)) def callback_right(self, data): """Handle request for speed change of right motor.""" self._right_motor_speed = data.data self._bus.write_word_data( EPUCK_I2C_ADDR, RIGHT_MOTOR_SPEED, PiPuckMotorServer.convert_speed(self._right_motor_speed)) def close_bus(self): """Close the I2C bus after the ROS Node is shutdown.""" self._bus.write_word_data(EPUCK_I2C_ADDR, LEFT_MOTOR_SPEED, 0) self._bus.write_word_data(EPUCK_I2C_ADDR, RIGHT_MOTOR_SPEED, 0) self._bus.close() @staticmethod def euler_to_quaternion(yaw, pitch, roll): """Convert euler angles of pitch, roll, and yaw to a quaternion. Based on code from https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles. We don't use tf.transforms here to reduce dependence on tf and increase performance on this simple task. """ c_y = cos(yaw * 0.5) s_y = sin(yaw * 0.5) c_p = cos(pitch * 0.5) s_p = sin(pitch * 0.5) c_r = cos(roll * 0.5) s_r = sin(roll * 0.5) q_w = c_y * c_p * c_r + s_y * s_p * s_r q_x = c_y * c_p * s_r - s_y * s_p * c_r q_y = s_y * c_p * s_r + c_y * s_p * c_r q_z = s_y * c_p * c_r - c_y * s_p * s_r return Quaternion(x=q_x, y=q_y, z=q_z, w=q_w) def run(self): """ROS Node server.""" initial_left_steps = int( self._bus.read_word_data(EPUCK_I2C_ADDR, LEFT_MOTOR_STEPS)) initial_right_steps = int( self._bus.read_word_data(EPUCK_I2C_ADDR, RIGHT_MOTOR_STEPS)) # Initial steps are set to counter the fact that the node may have previously run and the # e-puck firmware will not necessarily have been reset. self._left_steps_previous = initial_left_steps self._right_steps_previous = initial_right_steps self._real_left_steps_previous = initial_left_steps self._real_right_steps_previous = initial_right_steps while not rospy.is_shutdown(): # Get current steps left_steps = int( self._bus.read_word_data(EPUCK_I2C_ADDR, LEFT_MOTOR_STEPS)) right_steps = int( self._bus.read_word_data(EPUCK_I2C_ADDR, RIGHT_MOTOR_STEPS)) # Get step measurement time measurement_time = rospy.get_time() # Check for overflows and underflows if left_steps + (MAX_MOTOR_STEPS_RAW / 2.0) < self._left_steps_previous: self._left_overflows += 1 elif left_steps > self._left_steps_previous + ( MAX_MOTOR_STEPS_RAW / 2.0): self._left_overflows -= 1 if right_steps + (MAX_MOTOR_STEPS_RAW / 2.0) < self._right_steps_previous: self._right_overflows += 1 elif right_steps > self._right_steps_previous + ( MAX_MOTOR_STEPS_RAW / 2.0): self._right_overflows -= 1 # Calculate the real steps left and right accounting for overflows real_left_steps = left_steps + self._left_overflows * MAX_MOTOR_STEPS_RAW real_right_steps = right_steps + self._right_overflows * MAX_MOTOR_STEPS_RAW # Publish raw and real steps self._steps_right_pub.publish(right_steps) self._steps_left_pub.publish(left_steps) self._real_steps_right_pub.publish(real_right_steps) self._real_steps_left_pub.publish(real_left_steps) # Calculate step changes delta_left = (real_left_steps - self._real_left_steps_previous) * MOTOR_STEP_DISTANCE delta_right = (real_right_steps - self._real_right_steps_previous ) * MOTOR_STEP_DISTANCE #Calculate delta steps and turn delta_theta = (delta_right - delta_left) / WHEEL_DISTANCE delta_steps = (delta_right + delta_left) / 2.0 # Update the estimate for x, y, and rotation self._estimate_x += delta_steps * cos(self._estimate_theta + delta_theta / 2.0) self._estimate_y += delta_steps * sin(self._estimate_theta + delta_theta / 2.0) self._estimate_theta += delta_theta # Update previous steps to current self._left_steps_previous = left_steps self._right_steps_previous = right_steps self._real_left_steps_previous = real_left_steps self._real_right_steps_previous = real_right_steps # Send odometry odometry_message = Odometry() odometry_message.pose.pose.orientation = PiPuckMotorServer.euler_to_quaternion( self._estimate_theta, 0, 0) odometry_message.pose.pose.position.x = self._estimate_x odometry_message.pose.pose.position.y = self._estimate_y odometry_message.twist.twist.linear.x = delta_steps / ( measurement_time - self._last_measurement_time) odometry_message.twist.twist.angular.z = delta_theta / ( measurement_time - self._last_measurement_time) odometry_message.header.frame_id = self._reference_frame self._odometry_pub.publish(odometry_message) self._last_measurement_time = measurement_time self._rate.sleep()
class SRF02: def __init__(self): self._i2c = SMBus(1) self._i2c_address = SRF02_I2C_ADDRESS self._waiting_for_echo = False yesterday = datetime.now() - timedelta(1) self._time_last_burst = yesterday # The last distance measurement self.distance = None # meters # On power up, the detection threshold is set to 28cm (11") self.mindistance = 0.28 # meters # This is mostly for debugging and testing self.num_bursts_sent = 0 # check that the sensor is present - read the version self.version = self._read_version() log.info("SRF-02 Ultrasonic Sensor initialized. Version: %d" % self.version) # we want to check how often we get exceptions self.error_counter = 0 # Should be called in some sensor loop, maybe at 100Hz. Is fast. # Will trigger an ultrasonic burst or check if we received an echo. # I we have a measurement, it is returned in meters. def update(self): distance = None now = datetime.now() time_since_last_burst = (now - self._time_last_burst).total_seconds() # log.debug("time since last burst: {}".format(time_since_last_burst)) if self._waiting_for_echo: # make sure we wait at least some amount of time before we read if time_since_last_burst > SRF02_MIN_TIME_BETWEEN_BURST_READ: # check if we have an echo distance = self._read_echo() # Fallback if we don't get an echo, just stop waiting # from the data sheet: # The SRF02 will always be ready 70mS after initiating the ranging. if distance is None and time_since_last_burst > SRF02_MAX_WAIT_TIME: log.warn("Fallback! Waited longer than 70ms!") self._waiting_for_echo = False if (not self._waiting_for_echo) and time_since_last_burst > SRF02_MIN_TIME_BETWEEN_BURSTS: self._send_burst() expected_error = self._calc_expected_error(distance) return distance, expected_error def _send_burst(self): self._i2c.write_byte_data(self._i2c_address, 0, 0x51) self._waiting_for_echo = True self._time_last_burst = datetime.now() self.num_bursts_sent += 1 log.debug("Burst sent.") def _read_echo(self): # it must be possible to read all of these data in 1 i2c transaction # buf[0] software version. If this is 255, then the ping has not yet returned # buf[1] unused # buf[2] high byte range # buf[3] low byte range # buf[4] high byte minimum auto tuned range # buf[5] low byte minimum auto tuned range # We use the version information to detect if the result is there yet. # 255 is a dummy version for the case that no echo has been received yet. For me, the real version is "6". if self._read_version() == 255: log.debug("Version is 255") return None self.distance = self._i2c.read_word_data(self._i2c_address, 2) / 255 self.mindistance = self._i2c.read_word_data(self._i2c_address, 4) / 255 # A value of 0 indicates that no objects were detected. We prefer None to represent this. if self.distance == 0: self.distance = None self._waiting_for_echo = False log.debug("echo received! distance is: {}".format(self.distance)) return self.distance # The version can be read from register 0. # Reading it has no real value for us, but we can use it to determine if a measurement is finished or not. def _read_version(self): try: return self._i2c.read_byte_data(self._i2c_address, 0) # 255 means that the unit is still measuring the distance except IOError: log.error("Recovering from IOError") self.error_counter += 1 return 255 # find out what kind of error we expect (used in sensor fusion) def _calc_expected_error(self, distance): # no reading at all if distance is None: return SENSOR_ERROR_MAX # object too close if distance <= self.mindistance: return SRF02_SENSOR_ERROR_LOW_RANGE # good distance, nice measurement elif distance <= SRF02_MAX_RANGE: return SRF02_SENSOR_ERROR_GOOD_RANGE # object too far else:
def getTempurature(self): bus = SMBus(1) self.tempurature = self.decodePMBus( bus.read_word_data(self.address, 0x8D)) bus.close() return self.tempurature
class templogger(): _cal_AC1 = 0 _cal_AC2 = 0 _cal_AC3 = 0 _cal_AC4 = 0 _cal_AC5 = 0 _cal_AC6 = 0 _cal_B1 = 0 _cal_B2 = 0 _cal_MB = 0 _cal_MC = 0 _cal_MD = 0 bmp180 = 0 bh1750 = 0 lm75addr = 0 i2c1 = 0 db = 0 api = 0 feed = 0 tempds = 0 lightds = 0 pressds = 0 def __init__(self, filename): self.lm75addr = 0x4f self.db = sqlite3.connect(filename) self.db.execute("CREATE TABLE IF NOT EXISTS temp_series(date datetime, event TEXT, value REAL, detail TEXT)") self.db.commit() self.bmp180 = 0x77 self.bh1750 = 0x23 self.i2c1 = SMBus(1) self.calibration() #self.api = xively.XivelyAPIClient(api_key) #self.feed = self.api.feeds.get(feed_id) #self.tempds = self.get_datastream(self.feed, "Temperature") #self.lightds = self.get_datastream(self.feed, "Light") #self.pressds = self.get_datastream(self.feed, "Pressure") def get_datastream(self, feed, name): try: datastream = feed.datastreams.get(name) return datastream except: datastream = feed.datastreams.create(name, tags="") return datastream def publish(self, datastream, value, time): datastream.current_value = value datastream.at = time try: datastream.update() except requests.HTTPError as e: print "HTTPError({0}): {1}".format(e.errno, e.strerror) def calibration(self): self._cal_AC1 = self.read_16bit_regs(self.bmp180, 0xaa) self._cal_AC2 = self.read_16bit_regs(self.bmp180, 0xac) self._cal_AC3 = self.read_16bit_regs(self.bmp180, 0xae) self._cal_AC4 = self.read_16bit_regu(self.bmp180, 0xb0) self._cal_AC5 = self.read_16bit_regu(self.bmp180, 0xb2) self._cal_AC6 = self.read_16bit_regu(self.bmp180, 0xb4) self._cal_B1 = self.read_16bit_regs(self.bmp180, 0xb6) self._cal_B2 = self.read_16bit_regs(self.bmp180, 0xb8) self._cal_MB = self.read_16bit_regs(self.bmp180, 0xba) self._cal_MC = self.read_16bit_regs(self.bmp180, 0xbc) self._cal_MD = self.read_16bit_regs(self.bmp180, 0xbe) def readRawTemp(self): self.i2c1.write_byte_data(self.bmp180, 0xf4, 0x2e) time.sleep(0.005) raw = self.read_16bit_regu(self.bmp180, 0xf6) return raw def readTemperature(self): ut = self.readRawTemp() x1 = ((ut - self._cal_AC6) * self._cal_AC5) >> 15 x2 = (self._cal_MC << 11) / (x1 + self._cal_MD) b5 = x1 + x2 temp = ((b5 + 8) >> 4)/10.0 return temp def readRawPressure(self): self.i2c1.write_byte_data(self.bmp180, 0xf4, 0xf4) #Read ultra high resolution time.sleep(0.026) msb = self.i2c1.read_byte_data(self.bmp180, 0xf6) lsb = self.i2c1.read_byte_data(self.bmp180, 0xf7) xlsb = self.i2c1.read_byte_data(self.bmp180, 0xf8) raw = (msb << 16) + (lsb << 8) + (xlsb) >> 5 return raw def readPressure(self): # Get raw temperature and pressure ut = self.readRawTemp() up = self.readRawPressure() # Convert to actual compensated and calibrated pressure (see Datasheet) x1 = ((ut - self._cal_AC6) * self._cal_AC5) >> 15 x2 = (self._cal_MC << 11) / (x1 + self._cal_MD) b5 = x1 + x2 b6 = b5 - 4000 x1 = (self._cal_B2 * (b6 * b6) >> 12) >> 11 x2 = (self._cal_AC2 * b6) >> 11 x3 = x1 + x2 b3 = (((self._cal_AC1 * 4 + x3) << 3) + 2) / 4 x1 = (self._cal_AC3 * b6) >> 13 x2 = (self._cal_B1 * ((b6 * b6) >> 12)) >> 16 x3 = ((x1 + x2) + 2) >> 2 b4 = (self._cal_AC4 * (x3 + 32768)) >> 15 b7 = (up - b3) * (50000 >> 3) if (b7 < 0x80000000): p = (b7 * 2) / b4 else: p = (b7 / b4) * 2 x1 = (p >> 8) * (p >> 8) x1 = (x1 * 3038) >> 16 x2 = (-7357 * p) >> 16 p = p + ((x1 + x2 + 3791) >> 4) return p def readLM75Temperature(self): # Measure temperature temp = self.i2c1.read_word_data(self.lm75addr,0) # Swap lower and higher byte temp = (((temp & 0xff) << 8)|((temp >> 8) & 0xff)) value = temp >> 5 # Make signed integer if (temp & 0x8000): # one's complement value = (~value & 0x1FF) # two's complement value = value - 1 # significance: means negative temp value = -value value = value / 8.0 return value def readBH1750Light(self): # Measure light luxtmp = self.i2c1.read_word_data(self.bh1750, 0x10) # Convert to actual lux (see Datasheet) lux = (((luxtmp >> 8) & 0xff) | ((luxtmp & 0xff) << 8))/1.2 return lux def measure(self): thisdate = datetime.datetime.utcnow() nu = datetime.datetime.utcnow() print(thisdate) value = self.readLM75Temperature() #self.publish(self.tempds, value, nu) self.db.execute( 'INSERT INTO temp_series(date, event, value, detail) VALUES(?,?,?,?)', ( thisdate, "Temperature", value, "Green House" ) ) self.db.commit() lux = self.readBH1750Light() #self.publish(self.lightds, lux, nu) self.db.execute( 'INSERT INTO temp_series(date, event, value, detail) VALUES(?, ?, ?, ?)', ( thisdate, "Light intensity", lux, "Greenhouse" ) ) self.db.commit() pressure = self.readPressure() #self.publish(self.pressds, pressure, nu) self.db.execute( 'INSERT INTO temp_series(date, event, value, detail) VALUES(?, ?, ?, ?)', ( thisdate, "Pressure", pressure, "Greenhouse" ) ) self.db.commit() def print_climate(self): print "The temperature is: %i Degrees Celsius" % (self.readLM75Temperature()) print "The light intensity is: %i Lux" % (self.readBH1750Light()) print "The pressure is: %i Pascal" % (self.readPressure()) def read_16bit_regu(self, address, register): a = self.i2c1.read_byte_data(address, register) b = self.i2c1.read_byte_data(address, register+1) return ((a << 8) | b) def read_16bit_regs(self, address, register): a = self.i2c1.read_byte_data(address, register) b = self.i2c1.read_byte_data(address, register+1) c = (a << 8)|b if (c & 0x8000): c = (~c & 0xffff) c = c-1 c = -c return c
class I2CDevice(object): """ Class for communicating with an I2C device. Allows reading and writing 8-bit, 16-bit, and byte array values to registers on the device. It can handle signed, unsigned and endianness. :var uint address: Assigned I2C address. :var uint8 busid: Assigned IC2 bus identifier. :param uint address: I2C address. :param uint busid: IC2 bus identifier. :param class i2c_class: Class implementing the I2C reading interface. If None, smbus.SMBus will be used. """ def __init__(self, busnum, address, i2c_class=None): self._busnum = busnum self._address = address if i2c_class is None: from smbus import SMBus self._bus = SMBus(busnum) else: self._bus = i2c_class(busnum) self._logger = logging.getLogger( '/dev/i2c-{}/{:#x}'.format(busnum, address) ) def _debug(self): self._logger.setLevel(logging.DEBUG) self._logger.addHandler(logging.StreamHandler()) @property def busnum(self): return self._busnum @property def address(self): return self._address def write(self, value): """ Write the specified 8-bit value to the device base address. """ assert bound_bits(value, 8) self._bus.write_byte(self._address, value) self._logger.debug( 'Wrote value {:#x}'.format(value) ) def register_write_u8(self, register, value): """ Write an 8-bit value to the specified 8-bit register. """ assert bound_bits(register, 8) assert bound_bits(value, 8) self._bus.write_byte_data(self._address, register, value) self._logger.debug( 'Wrote to register {:#x} value {:#x}'.format(register, value) ) def register_write_u16(self, register, value): assert bound_bits(register, 8) assert bound_bits(value, 16) self._bus.write_word_data(self._address, register, value) self._logger.debug( 'Wrote to register pair {:#x}, {:#x} value {:#x} '.format( register, register + 1, value ) ) def read(self): """ Read the device base address and return a 8-bit value. """ result = self._bus.read_byte(self._address) & 0xFF self._logger.debug( 'Read value {:#x}'.format(result) ) return result def register_read_u8(self, register): """ Read the specified 8-bit register and return a 8-bit value. """ assert bound_bits(register, 8) result = self._bus.read_byte_data(self._address, register) & 0xFF self._logger.debug( 'Read from register {:#x} returns {:#x}'.format(register, result) ) return result def register_read_s8(self, register): """ Read the specified 8-bit register and return a signed 7-bit value. """ result = self.register_read_u8(register) if result > 127: result -= 256 self._logger.debug('... as signed: {:#x}'.format(result)) return result def register_read_u16(self, register, little_endian=True): """ Read the specified 8-bit register and return a 16-bit value with the specified endianness. Default is little endian, or least significant byte first. """ assert bound_bits(register, 8) result = self._bus.read_word_data(self._address, register) & 0xFFFF self._logger.debug( 'Read from register pair {:#x}, {:#x} value {:#x} '.format( register, register + 1, result ) ) # Swap bytes if using big endian because read_word_data assumes little # endian on ARM (little endian) systems. if not little_endian: result = ((result << 8) & 0xFF00) + (result >> 8) self._logger.debug('... as big endian: {:#x}'.format(result)) return result def register_read_s16(self, register, little_endian=True): """ Read the specified 8-bit register and return a signed 15-bit value with the specified endianness. Default is little endian, or least significant byte first. """ result = self.register_read_u16(register, little_endian) if result > 32767: result -= 65536 self._logger.debug('... as signed: {:#x}'.format(result)) return result def register_read_u16le(self, register): """ Same as register_read_u16 with endianness set to little endian. """ return self.register_read_u16(register, little_endian=True) def register_read_u16be(self, register): """ Same as register_read_u16 with endianness set to big endian. """ return self.register_read_u16(register, little_endian=False) def register_read_s16le(self, register): """ Same as register_read_s16 with endianness set to little endian. """ return self.register_read_s16(register, little_endian=True) def register_read_s16be(self, register): """ Same as register_read_s16 with endianness set to big endian. """ return self.register_read_s16(register, little_endian=False)
class LinuxI2cBus: """A Linux I²C device, which is itself an I²C bus. Should not be instantiated directly; use `LinuxI2c.find_devices` instead. This type mimics the `smbus.SMBus` read/write/close APIs. However, `open` does not take any parameters, and not all APIs are available. """ # note: this is not a liquidctl BaseBus, as that would cause # find_liquidctl_devices to try to directly instantiate it def __init__(self, i2c_dev): self._i2c_dev = i2c_dev self._smbus = None try: assert i2c_dev.name.startswith('i2c-') self._number = int(i2c_dev.name[4:]) except: raise ValueError(f'cannot infer bus number') def find_devices(self, drivers, **kwargs): """Probe drivers and find compatible devices in this bus.""" for drv in drivers: yield from drv.probe(self, **kwargs) def open(self): """Open the I²C bus.""" if not self._smbus: try: self._smbus = SMBus(self._number) except FileNotFoundError: if Path('/sys/class/i2c-dev').exists(): raise raise OSError('kernel module i2c-dev not loaded') from None def read_byte(self, address): """Read a single byte from a device.""" value = self._smbus.read_byte(address) _LOGGER.debug('read byte @ 0x%02x: 0x%02x', address, value) return value def read_byte_data(self, address, register): """Read a single byte from a designated register.""" value = self._smbus.read_byte_data(address, register) _LOGGER.debug('read byte data @ 0x%02x:0x%02x: 0x%02x', address, register, value) return value def read_word_data(self, address, register): """Read a single 2-byte word from a given register.""" value = self._smbus.read_word_data(address, register) _LOGGER.debug('read word data @ 0x%02x:0x%02x: 0x%04x', address, register, value) return value def read_block_data(self, address, register): """Read a block of up to 32 bytes from a given register.""" data = self._smbus.read_block_data(address, register) _LOGGER.debug('read block data @ 0x%02x:0x%02x: %r', address, register, LazyHexRepr(data)) return data def write_byte(self, address, value): """Write a single byte to a device.""" _LOGGER.debug('writing byte @ 0x%02x: 0x%02x', address, value) return self._smbus.write_byte(address, value) def write_byte_data(self, address, register, value): """Write a single byte to a designated register.""" _LOGGER.debug('writing byte data @ 0x%02x:0x%02x: 0x%02x', address, register, value) return self._smbus.write_byte_data(address, register, value) def write_word_data(self, address, register, value): """Write a single 2-byte word to a designated register.""" _LOGGER.debug('writing word data @ 0x%02x:0x%02x: 0x%04x', address, register, value) return self._smbus.write_word_data(address, register, value) def write_block_data(self, address, register, data): """Write a block of byte data to a given register.""" _LOGGER.debug('writing block data @ 0x%02x:0x%02x: %r', address, register, LazyHexRepr(data)) return self._smbus.write_block_data(address, register, data) def close(self): """Close the I²C connection.""" if self._smbus: self._smbus.close() self._smbus = None def load_eeprom(self, address): """Return EEPROM name and data in `address`, or None if N/A.""" # uses kernel facilities to avoid directly reading from the EEPROM # or managing its pages, also avoiding the need for unsafe=smbus dev = f'{self._number}-{address:04x}' try: name = self._i2c_dev.joinpath(dev, 'name').read_text().strip() eeprom = self._i2c_dev.joinpath(dev, 'eeprom').read_bytes() return LinuxEeprom(name, eeprom) except Exception as err: return None @property def name(self): return self._i2c_dev.name @property def description(self): return self._try_sysfs_read('name') @property def parent_vendor(self): return self._try_sysfs_read_hex('device/vendor') @property def parent_device(self): return self._try_sysfs_read_hex('device/device') @property def parent_subsystem_vendor(self): return self._try_sysfs_read_hex('device/subsystem_vendor') @property def parent_subsystem_device(self): return self._try_sysfs_read_hex('device/subsystem_device') @property def parent_driver(self): try: return Path( os.readlink(self._i2c_dev.joinpath('device/driver'))).name except FileNotFoundError: return None def __str__(self): if self.description: return f'{self.name}: {self.description}' return self.name def __repr__(self): def hexid(maybe): if maybe is not None: return f'{maybe:#06x}' return 'None' return f'{self.__class__.__name__}: name: {self.name!r}, ' \ f'description: {self.description!r}, ' \ f'parent_vendor: {hexid(self.parent_vendor)}, ' \ f'parent_device: {hexid(self.parent_device)}, ' \ f'parent_subsystem_vendor: {hexid(self.parent_subsystem_vendor)}, ' \ f'parent_subsystem_device: {hexid(self.parent_subsystem_device)}, ' \ f'parent_driver: {self.parent_driver!r}' def _try_sysfs_read(self, *sub, default=None): try: return self._i2c_dev.joinpath(*sub).read_text().rstrip() except FileNotFoundError: return default def _try_sysfs_read_hex(self, *sub, default=None): try: return int(self._i2c_dev.joinpath(*sub).read_text(), base=16) except FileNotFoundError: return default
class I2CBus: # The device ids supported # Note: Under linux, the enumeration of the i2c devices is not guaranteed to match the BBB device id, i.e., i2c0 may # not map to /dev/i2c-0. Here is a link on this topic: https://datko.net/2013/11/03/bbb_i2c # What is important from a software perspective is that pins and the device id match since we don't use the linux # device name. That is, we need to use an id, 0, 1, 2, which corresponds to a specific device connected on specific # pins. # Note: I2C device 0 is not enabled by default. There is a way to enable it (see above) but there are also possible # conflicts with existing capes. DEV_I2C_0 = 0 DEV_I2C_1 = 1 DEV_I2C_2 = 2 # The following formatting is taken from struct and maps the character designations to number of bytes in the type __TYPE_SIZES = {'d': 8, # double - 8 bytes 'f': 4, # float - 4 bytes 'L': 4, # uint32 - 4 bytes 'l': 4, # int32 - 4 bytes 'H': 2, # uint16 - 2 bytes 'h': 2, # int16 - 2 bytes 'B': 1, # uint8 - 1 byte 'b': 1 # int8 - 1 byte } def __init__(self, device): try: self._smbus = SMBus(device) except RuntimeError: raise I2CBusError("Unable to open SMBus using {}".format(device)) def _read_multiple_bytes(self, address, offset, num_bytes): return self._smbus.read_i2c_block_data(address, offset, num_bytes) def _write_multiple_bytes(self, address, offset, byte_values): self._smbus.write_i2c_block_data(address, offset, list(byte_values)) def WriteUint8(self, address, offset, value): self._smbus.write_byte_data(address, offset, value) def WriteUint16(self, address, offset, value): self._smbus.write_word_data(address, offset, value) def WriteInt16(self, address, offset, value): self._smbus.write_word_data(address, offset, value) def WriteUint32(self, address, offset, value): bytes = bytearray(struct.pack('L', value)) self._write_multiple_bytes(address, offset, bytes) def WriteFloat(self, address, offset, value): bytes = bytearray(struct.pack('f',value)) self._write_multiple_bytes(address, offset, bytes) def WriteArray(self, address, offset, values, type, endian=sys.byteorder): # Convert each value to its byte representation and place into a bytearray before writing to the bus # Note: struct.pack returns a string representation of the value. For a 1-byte value, it is a # string representation of 1 byte, for a 2 or 4 byte value, it is a 2-byte of 4-byte representation # Therefore, it is necessary to concatentate the strings before converting to a bytearray if endian == 'little': format = '<'+type else: format = '>'+type byte_values = '' for value in values: byte_values += struct.pack(format, value) self._write_multiple_bytes(address, offset, bytearray(byte_values)) def ReadUint8(self, address, offset): return self._smbus.read_byte_data(address, offset) def ReadUint16(self, address, offset): return self._smbus.read_word_data(address, offset) def ReadInt16(self, address, offset): return self._smbus.read_word_data(address, offset) def ReadUint32(self, address, offset): bytes = self._read_multiple_bytes(address, offset, I2CBus.__TYPE_SIZES['L']) return struct.unpack('L', str(bytearray(bytes)))[0] def ReadInt32(self, address, offset): bytes = self._read_multiple_bytes(address, offset, I2CBus.__TYPE_SIZES['l']) return struct.unpack('l', str(bytearray(bytes)))[0] def ReadFloat(self, address, offset): values = self._read_multiple_bytes(address, offset, I2CBus.__TYPE_SIZES['f']) return struct.unpack('f', str(bytearray(values)))[0] def ReadArray(self, address, offset, num_values, type, endian=sys.byteorder): # Create a format specifier based on the number of values requested. # All of the values will be read as the same type, e.g., all floats, all long, etc # The format specifies the number of float values to convert format = '%s%s' % (num_values, type) # Calculate number of bytes to read # - num_values is the number of values to read # - num_bytes is num_values * size of each value num_bytes = num_values * I2CBus.__TYPE_SIZES[type] # It turns out that reading i2c block data is not supported on all Raspberry Pi's (probably a OS/driver difference) # The Pi 2 running Jessie doesn't support i2c (i2cget with no arguments shows no 'i' option) # The Pi 3 running Jessie does support i2c (i2cget with no argument shows 'i' option) # So, we need to support both options bytes = self._read_multiple_bytes(address, offset, num_bytes) # Match the endianess of the request. Default is platform endianess # struct provides a format specifier for endianess if endian == 'little': format = '<'+format else: format = '>'+format return list(struct.unpack(format, str(bytearray(bytes))))