class Motors: def __init__(self, motorsList): self.motors = motorsList self.motorCount = 0 self.bus = SMBus(1) def start_motor(self): if self.motorCount < self.motors.count: self.bus.write_byte(self.motors[self.motorCount], 0x01) def add_counter(self): if self.motorCount < len(self.motors) - 1: self.motorCount += 1 else: self.motorCount = 0 def read_motor_info(self): b = self.bus.read_byte(self.motors[self.motorCount]) return b def set_status_counter(self): self.bus.write_byte(self.motors[self.motorCount], 0x02) def set_status_sensor(self): self.bus.write_byte(self.motors[self.motorCount], 0x03) def set_status_reset(self): self.bus.write_byte(self.motors[self.motorCount], 0x09) def get_actual_status(self): b = self.bus.read_byte(self.motors[self.motorCount]) return b
def scan(bus_num, start=0x03, end=0x78): try: bus = SMBus(bus_num) except PermissionError: print("Permission error!") sys.exit() print("I2C bus : " + str(bus_num)) print("Start address : " + hex(start)) print("End address : " + hex(end) + "\n") for i in range(start, end): val = 1 try: bus.read_byte(i) except OSError as e: val = e.args[0] finally: if val != 5: # No device if val == 1: res = "Available" elif val == 16: res = "Busy" elif val == 110: res = "Timeout" else: res = "Error code: " + str(val) print(hex(i) + " -> " + res)
def i2cdetect(bus_num): b = SMBus(bus_num) devs = [] for a in range(0xff): try: b.read_byte(a) devs.append(hex(a)) except IOError: pass return devs
def scan() -> List[str]: devices = [] try: bus = SMBus(1) # 1 indicates /dev/i2c-1 for device in range(128): try: bus.read_byte(device) devices.append(hex(device)) except: pass except FileNotFoundError as e: print("WARNING: I2C seems not to be activated") return devices
class Si7021Sensor: def __init__(self): self._bus = SMBus(1) self._address = 0x40 def __del__(self): self._bus.close() def _send_command(self, command_code): self._bus.write_byte(self._address, command_code) time.sleep(0.3) def _read_data(self): data0 = self._bus.read_byte(self._address) data1 = self._bus.read_byte(self._address) time.sleep(0.3) return data0, data1 def humidity(self): """ :return: relative humidity in percent. """ self._send_command(0xF5) data0, data1 = self._read_data() humidity = ((data0 * 256 + data1) * 125 / 65536.0) - 6 return humidity def temperature(self): """ :return: temperature in celsius degrees. """ self._send_command(0xF3) data0, data1 = self._read_data() cels_temp = ((data0 * 256 + data1) * 175.72 / 65536.0) - 46.85 return cels_temp
class i2c_device: def __init__(self, addr, port=I2CBUS): self.addr = addr self.bus = SMBus(port) # Write a single command def write_cmd(self, cmd): self.bus.write_byte(self.addr, cmd) sleep(0.0001) # Write a command and argument def write_cmd_arg(self, cmd, data): self.bus.write_byte_data(self.addr, cmd, data) sleep(0.0001) # Write a block of data def write_block_data(self, cmd, data): self.bus.write_block_data(self.addr, cmd, data) sleep(0.0001) # Read a single byte def read(self): return self.bus.read_byte(self.addr) # Read def read_data(self, cmd): return self.bus.read_byte_data(self.addr, cmd) # Read a block of data def read_block_data(self, cmd): return self.bus.read_block_data(self.addr, cmd)
def start_RFID(): global current_rfid global prev_rfid bus = SMBus(0) time.sleep(1) ok = True id = "" while True: try: gled.value = False print("reading...") start = time.time() b = bus.read_byte(0x41) id += chr(b) print("read", chr(b)) if (len(id)) % 2 == 1: gled.value = True else: gled.value = False if ok == False and len(id) == 15 or len(id) == 16: rfid = id[-8:] id = "" ok = True lock.acquire() current_rfid = rfid lock.release() gled.value = True time.sleep(3) print("RFID Scanned: ", rfid, id) elif len(id) == 16: rfid = id[-8:] lock.acquire() current_rfid = rfid lock.release() id = "" ok = True gled.value = True time.sleep(3) print("RFID Scanned: ", rfid) except Exception as e: print(e) end = time.time() #print(end-start) if (end - start > 2): print("resetting prev_rfid") lock.acquire() prev_rfid = "" current_rfid = "" lock.release() ok = False continue
def scan_i2c_bus(): bus = SMBus(1) L = [] for i in range(3,127): try: b = bus.read_byte(i) L.append(i) except IOError: continue bus.close() return L
def main(argv): print("Hello world!") bus = SMBus(1) for i in range(0, 128, 16): vals = [] for j in range(0, 16): res = True try: k = i + j if (k >= 0x30 and k <= 0x37) or (k >= 0x50 and k <= 0x5f): bus.read_byte(i + j) else: bus.write_byte(i + j, 0) except Exception as e: res = False if res: vals.append("{}: {:3}".format(j, i + j)) else: vals.append("{}: ---".format(j)) print("{:3}".format(i), ", ".join(vals))
class VCNL4010: """Vishay VCNL4010 proximity and ambient light sensor.""" def __init__(self): self._device = SMBus(1) self.led_current = 20 self.frequency = FREQUENCY_390K625 self.write(_VCNL4010_INTCONTROL, 0x08) def read(self, address): # Read an 8-bit unsigned value from the specified 8-bit address. with SMBus(1) as self._device: read = self._device.read_byte_data(_VCNL4010_I2CADDR_DEFAULT, address) return read def write(self, address, val): # Write an 8-bit unsigned value to the specified 8-bit address. with SMBus(1) as self._device: self._device.write_byte_data(_VCNL4010_I2CADDR_DEFAULT, address, val) def read_16(self, address): with SMBus(1) as self._device: read_block = self._device.read_i2c_block_data( _VCNL4010_I2CADDR_DEFAULT, address, 2) return (read_block[0] << 8) | read_block[1] def read_byte(self, address): with SMBus(1) as self._device: read = self._device.read_byte(address) @property def proximity(self): """The detected proximity of an object in front of the sensor. This is a unit-less unsigned 16-bit value (0-65535) INVERSELY proportional to the distance of an object in front of the sensor (up to a max of ~200mm). For example a value of 10 is an object farther away than a value of 1000. Note there is no conversion from this value to absolute distance possible, you can only make relative comparisons. """ # Clear interrupt. status = self.read(_VCNL4010_INTSTAT) status &= ~0x80 self.write(_VCNL4010_INTSTAT, status) # Grab a proximity measurement. self.write(_VCNL4010_COMMAND, _VCNL4010_MEASUREPROXIMITY) # Wait for result, then read and return the 16-bit value. while True: result = self.read(_VCNL4010_COMMAND) if result & _VCNL4010_PROXIMITYREADY: return self.read(_VCNL4010_PROXIMITYDATA)
def main(): # Initialize I2C (SMBus) bus = SMBus(1) arduino_addr = 0x7f arduino_status = -1 while arduino_status < 255: try: print("Requesting status: ", end='') arduino_status = bus.read_byte(arduino_addr) #print(type(bus.read_byte(arduino_addr))) except OSError: print("OSError: Failed to read from specified peripheral") print("status:", arduino_status) sleep(.05) # Take a picture
class WiiController: def __init__(self, delay=0.05): self.delay = delay if rpi.RPI_REVISION == 1: i2c_bus = 0 elif rpi.RPI_REVISION == 2: i2c_bus = 1 elif rpi.RPI_REVISION == 3: i2c_bus = 1 else: raise OSError("Unable to determine Raspberry Pi revision.") self.bus = SMBus(i2c_bus) self.bus.write_byte_data(0x52, 0x40, 0x00) time.sleep(0.1) @cached(TTLCache(maxsize=1, ttl=0.0166)) def read(self): self.bus.write_byte(0x52, 0x00) time.sleep(self.delay) return [(0x17 + (0x17 ^ self.bus.read_byte(0x52))) % 256 for _ in range(6)]
class PCF8754: def __init__(self, address, busnum=1): self._address = address self._i2c = SMBus(busnum) self._access_error = False def set_out(self, output): try: self._i2c.write_byte(self._address, (~output & 0xFF)) self._access_error = False except OSError: if not self._access_error: self._access_error = True log.warning('I2C device at address ' + str(hex(self._address)) + ' could not be accessed.') # print('I2C device at address ' + str(hex(self._address)) + ' could not be accessed.') return self._access_error def get_out(self): try: value = ~self._i2c.read_byte(self._address) & 0xFF self._access_error = False except OSError: if not self._access_error: self._access_error = True log.warning('I2C device at address ' + str(hex(self._address)) + ' could not be accessed.') # print('I2C device at address ' + str(hex(self._address)) + ' could not be accessed.') value = 0x00 return value, self._access_error
#_READ_USER1 = const(0xE7) #_USER1_VAL = const(0x3A) #with SMBus(1) as bus: # # Write a byte to address 80, offset 0 # print("immabus") # bus.write_byte_data(HTU21D_ADDR, 0, resetbin) # Open i2c bus 1 and read one byte from address 80, offset 0 bus = SMBus(1) #b = bus.read_byte_data(40, 0) #print(b) #bus.close() for device in range(254): try: bus.read_byte(device) print(hex(device)) except: # exception if read_byte fails pass #b = bus.write_byte_data(64, 1) #bus.write_byte_data(80, 0, data) #print(b) #bus.close()
from utils import bytes_to_str addr = 0x9 # bus address bus = SMBus(1) # indicates /dev/ic2-1 bus.write_byte(addr, 0) bus.write_byte(addr, 0) time.sleep(.1) estimated_value = 1 while True: # data = bus.read_word_data(addr,0) data = bus.read_i2c_block_data(addr, 1, 2) b1 = bus.read_byte(addr) b2 = bus.read_byte(addr) # val = struct.unpack('h', b1 + b2)[0] val = b2 + (b1 << 8) s = bytes_to_str(b1, b2) print(s + " | " + str(val) + " | " + str(estimated_value)) assert (estimated_value == val) estimated_value += 1 # data = bus.read_i2c_block_data(addr, 0, 1) time.sleep(.01) # bus.write_byte(addr, 0x1) # switch it on # input("Press return to exit") # bus.write_byte(addr, 0x0) # switch it on
import time from smbus2 import SMBus address = 0x48 A0 = 0x40 A1 = 0x41 A2 = 0x42 A3 = 0x43 bus = SMBus(1) while True: bus.write_byte(address, A0) value = bus.read_byte(address) if (value < 3): print("- No Pressure") elif (value < 50): print("- Light Touch") elif (value < 125): print("- Light Squeeze") elif (value < 200): print("- Meduim Squeeze") else: print("- Big Squeeze") time.sleep(1)
def adcReadInit(bus, i2c_addr, slave_addr, adc_ch): '''Reads data from ADC. \nbus -> SMBus object \ni2c_addr -> hex adress of i2c connection (i.e. 0x12) \nslave_addr -> configuration of A0-A2 in string form (i.e. '010') \nadc_ch -> channel where adc is connected (0-3)''' addr_byte = '0b1001' + slave_addr + '1' addr_byte = int(addr_byte, 2) control_byte = adc_ch bus.write_byte(i2c_addr, addr_byte) bus.write_byte(i2c_addr, control_byte) def getSample(bus, i2c_addr): return bus.read_byte(i2c_addr) bus = SMBus(1) adcReadInit(bus, 0X48, '000', 0) samples = [] s = timer() i = 0 while timer() - s < 1: sample = bus.read_byte(0x48) i += 1 #print("Input level: %s" % sample) print(i)
def I2C_setup(i2c_bus, i2c_address, i2c_channel_setup): address = 0x70 + i2c_address % 10 bus = SMBus(i2c_bus) bus.write_byte(address, i2c_channel_setup) time.sleep(0.1) print("TCA9548A I2C channel status:{}".format(bin(bus.read_byte(address))))
from smbus2 import SMBus bus = SMBus(1) ADDRESS = 0x19 bus.write_byte(ADDRESS, 0xaa) b = bus.read_byte(ADDRESS) assert b == 0xaa print("Read byte and write byte OK") b = bus.read_byte_data(ADDRESS, 1) assert b == 0xaa print("Read byte data@1 OK") bus.write_byte_data(ADDRESS, 4, 0x44) b = bus.read_byte_data(ADDRESS, 1) assert b == 0x44 print("Write byte data@4 OK") bus.write_byte_data(ADDRESS, 5, 0x55) b = bus.read_byte_data(ADDRESS, 2) assert b == 0x55 print("Write byte data@5 OK") bus.write_byte_data(ADDRESS, 6, 0x66) b = bus.read_byte_data(ADDRESS, 3) assert b == 0x66 print("Write byte data@6 OK")
class PilotSensors(object): # _rss_feed_src = './habrahabr.xml' # _rss_refrash_int = 60 # in seconds _rss_refrash_int = 300 # in seconds _alarms = PilotAlarms() _alarm_proc = None _alarm_in_reproduction = Value(c_bool, False) _photores_approx_arr = [] _photores_DEV_ADDR = 0x48 _adc_channels = { 'AIN0': 0b1000000, # 0x40 (photo-resistor) 'AIN1': 0b1000001, # 0x41 (not connected) 'AIN2': 0b1000010, # 0x42 (not connected) 'AIN3': 0b1000011, # 0x43 (not connected) } _dac_channel = 0b1000000 # 0x40 _therm_sensors_base_dir = '/sys/devices/w1_bus_master1' _therm_sensor_ids = [ '000001ac0d2d', # Indoor sensor ID '000001ac5f3a' ] # Outdoor sensor ID def __init__(self): if os.name == 'nt': self._devel = True else: self._devel = False self._bus = SMBus(1) # 1 for RPi model B rev.2 # Starting photoresistor process self._photores_proc_enable = Value(c_bool, True) self._photores_proc_val = Value(c_int, 0xFF) self._photores_proc = Process(target=self.lightProc, args=(self._photores_proc_enable, self._photores_proc_val, 20)) self._photores_proc.start() # Starting RSS feed reader process self._rss_proc_enable = Value(c_bool, True) self._rss_proc_feed_src = MpArray(c_char, bytearray(255)) self._rss_proc_feed_src.value = 'https://news.yandex.ru/index.rss'.encode( 'cp1251') self._rss_proc_val = MpArray(c_char, bytearray(255)) self._rss_proc = Process( target=self.rssProc, args=(self._rss_proc_enable, self._rss_proc_feed_src, self._rss_proc_val, self._rss_refrash_int)) self._rss_proc.start() # Starting DS18B20 thermosensors process self._therm_proc_enable = Value(c_bool, True) init_temps = [float(-99) for _ in range(len(self._therm_sensor_ids))] self._therm_proc_val = MpArray(c_double, init_temps) self._therm_proc = Process(target=self.thermProc, args=(self._therm_proc_enable, self._therm_proc_val, 60)) self._therm_proc.start() def stopSensors(self): """ The method of stopping all processes of sensors :return: """ print('Stop sensors...') if self._alarm_proc is not None and self._alarm_proc.pid is not None and self._alarm_proc.is_alive( ): self._alarm_proc.terminate() self._photores_proc_enable.value = False self._photores_proc.join() self._rss_proc.terminate() self._therm_proc_enable.value = False self._therm_proc.join() def alarm(self, atype='click'): """ Method for starting process of sound reproduction :param atype: Sets type of sound to play :return: """ atype = atype.lower() if type(atype) == str else 'click' if self._alarm_proc is not None and self._alarm_proc.pid is not None and self._alarm_proc.is_alive( ): self._alarm_proc.terminate() if atype == 'click': self._alarm_proc = Process(target=self._alarms.click, args=(self._alarm_in_reproduction, )) elif atype == 'config_accept': self._alarm_proc = Process(target=self._alarms.configAccept, args=(self._alarm_in_reproduction, )) elif atype == 'config_fail': self._alarm_proc = Process(target=self._alarms.configFail, args=(self._alarm_in_reproduction, )) elif atype == 'alarm1': self._alarm_proc = Process(target=self._alarms.clockAlarm, args=(self._alarm_in_reproduction, 1)) elif atype == 'alarm2': self._alarm_proc = Process(target=self._alarms.clockAlarm, args=(self._alarm_in_reproduction, 2)) if self._alarm_proc.pid is None: self._alarm_proc.start() def alarmInReproduction(self): """ Method for get current state of sound reproduction flag :return: Current state of sound reproduction """ return self._alarm_in_reproduction.value def getLight(self): """ Method of obtaining the current value of light intensity :return: Integer value in range from 0 to 255 """ return self._photores_proc_val.value def lightProc(self, proc_enable, proc_val, approx_length=20): """ Code of the logic for reading the ADC data to determine the light intensity :param proc_enable: Continued polling cycle flag :param proc_val: The communication variable with the main process for returning the value read from the ADC :param approx_length: Parameter specifying the number of values for obtaining the mean value of illumination in a time interval :return: """ while proc_enable.value: if self._devel: proc_val.value = 255 else: self._bus.write_byte(self._photores_DEV_ADDR, self._adc_channels['AIN0']) self._photores_approx_arr.append( self._bus.read_byte(self._photores_DEV_ADDR)) alen = len(self._photores_approx_arr) approx_val = sum(self._photores_approx_arr) / alen if alen > approx_length: self._photores_approx_arr = self._photores_approx_arr[ alen - approx_length:] proc_val.value = 255 - int(approx_val) time.sleep(0.1) def getRSSFeedSource(self): """ Method for get current value of RSS feed source variable :return: RSS feed URL """ return self._rss_proc_feed_src.value.decode('cp1251') def setRSSFeedSource(self, url): """ Method to set current value of RSS feed source variable :param url: RSS feed URL :return: """ self._rss_proc_feed_src.value = url.encode( 'cp1251') if type(url) is str else self._rss_proc_feed_src.value def getLastFeed(self): """ The method of obtaining the last title name of a record from RSS feed :return: Last title name of a RSS feed """ return self._rss_proc_val.value.decode('iso8859-5') def rssProc(self, proc_enable, rss_proc_feed_src, proc_val, get_inerval=300): """ Code of the logic for reading data from RSS feed channel :param proc_enable: Continued polling cycle flag :param rss_proc_feed_src: The communication variable with the main process for get/set the value RSS-channel source URL :param proc_val: The communication variable with the main process for returning the value read RSS-channel :param get_inerval: Sets the polling time interval :return: """ time.sleep(5) # Starting delay for accepting configuration interval = 0 replace_map = [('«', '"'), ('»', '"'), ('–', '-'), ('—', '-')] while proc_enable.value: if interval == 0: feed = feedparser.parse( rss_proc_feed_src.value.decode('cp1251')) feed_len = len(feed['entries']) if feed_len > 0: last_rec_title = str(feed['entries'][0]['title']).replace( '«', '"') for rep in replace_map: last_rec_title = last_rec_title.replace(rep[0], rep[1]) proc_val.value = bytes(last_rec_title[:255], encoding='iso8859-5', errors='replace') else: proc_val.value = bytes( 'А новостей на сегодня больше нет... или накрылся интернет :-(', encoding='iso8859-5', errors='replace') interval = interval + 1 if interval <= get_inerval else 0 time.sleep(1) def getTherms(self): """ The method of obtaining the list of values containing data from thermal sensors :return: list of float values temperature """ return [t for t in self._therm_proc_val] def thermProc(self, proc_enable, proc_val, get_interval=60): """ Code of the logic for obtaining data from thermal sensors :param proc_enable: Continued polling cycle flag :param proc_val: The communication variable with the main process for returning the value obtained from thermal sensors :param get_interval: Sets the polling time interval :return: """ interval = 0 s_paths = [ self._therm_sensors_base_dir + '/28-' + sid + '/w1_slave' for sid in self._therm_sensor_ids ] while proc_enable.value: if interval == 0: for i, sensor in enumerate(s_paths): if os.path.exists(sensor): try: with open(sensor, "r") as t_file: tdata = t_file.readlines() if tdata[0].strip()[-4:].strip() == "YES": proc_val[i] = float( tdata[1].split('=')[1]) / 1000 except IOError: pass interval = interval + 1 if interval <= get_interval else 0 time.sleep(1)
class Pca9546a(): def __init__(self, address): """Init smbus channel and Pca9546 driver on specified address.""" try: self.i2c_bus = SMBus(I2C_CHANNEL) self.i2c_address = address # whatever we see on RPi if self.read_config_register() is None: raise ValueError except ValueError: log.error("Pca9546 ERROR: No device found on address {}!".format( hex(address))) self.i2c_bus = None except: log.error( "Bus on channel {} is not available. Error raised by Pca9546.". format(I2C_CHANNEL)) log.info("Available busses are listed as /dev/i2c*") self.i2c_bus = None def __del__(self): """Driver destructor.""" self.i2c_bus = None def read_config_register(self): try: return self.i2c_bus.read_byte(self.i2c_address) except Exception as e: log.error( f"An exception occured when trying to read config register: {e}" ) return None def select_channel(self, val=None, ch0=0, ch1=0, ch2=0, ch3=0): """ Set internal register to desired combination of channels. """ if type(val) is not int: log.error(f"Input value must be an integer!") return False if val < 0 or val > 15: log.error( f"Specified channel configuration must be between 0000 (0 dec) and 1111 (15 dec)" ) return False if ch0 < 0 or ch0 > 1: log.error(f"Channel 0 must be set to either 0 or 1") return False if ch1 < 0 or ch1 > 1: log.error(f"Channel 1 must be set to either 0 or 1") return False if ch2 < 0 or ch2 > 1: log.error(f"Channel 2 must be set to either 0 or 1") return False if ch3 < 0 or ch3 > 1: log.error(f"Channel 3 must be set to either 0 or 1") return False if val is None: val = ch0 | (ch1 << 1) | (ch2 << 2) | (ch3 << 3) try: self.i2c_bus.write_byte(self.i2c_address, val) return True except Exception as e: log.error( f"An exception occured when trying to write config register: {e}" ) return False
class InputModule(AbstractInput): """ A sensor support class that measures the SHT2x's humidity and temperature and calculates the dew point """ def __init__(self, input_dev, testing=False): super(InputModule, self).__init__() self.logger = logging.getLogger("mycodo.inputs.sht2x") if not testing: from smbus2 import SMBus self.logger = logging.getLogger("mycodo.sht2x_{id}".format( id=input_dev.unique_id.split('-')[0])) self.device_measurements = db_retrieve_table_daemon( DeviceMeasurements).filter( DeviceMeasurements.device_id == input_dev.unique_id) self.i2c_address = int(str(input_dev.i2c_location), 16) self.i2c_bus = input_dev.i2c_bus self.sht2x = SMBus(self.i2c_bus) def get_measurement(self): """ Gets the humidity and temperature """ return_dict = measurements_dict.copy() for _ in range(2): try: # Send temperature measurement command # 0xF3(243) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF3) time.sleep(0.5) # Read data back, 2 bytes # Temp MSB, Temp LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) temperature = -46.85 + (( (data0 * 256 + data1) * 175.72) / 65536.0) # Send humidity measurement command # 0xF5(245) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF5) time.sleep(0.5) # Read data back, 2 bytes # Humidity MSB, Humidity LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) humidity = -6 + (((data0 * 256 + data1) * 125.0) / 65536.0) if self.is_enabled(0): return_dict[0]['value'] = temperature if self.is_enabled(1): return_dict[1]['value'] = humidity if (self.is_enabled(2) and self.is_enabled(0) and self.is_enabled(1)): return_dict[2]['value'] = calculate_dewpoint( return_dict[0]['value'], return_dict[1]['value']) if (self.is_enabled(3) and self.is_enabled(0) and self.is_enabled(1)): return_dict[3]['value'] = calculate_vapor_pressure_deficit( return_dict[0]['value'], return_dict[1]['value']) return return_dict except Exception as e: self.logger.exception( "Exception when taking a reading: {err}".format(err=e)) # Send soft reset and try a second read self.sht2x.write_byte(self.i2c_address, 0xFE) time.sleep(0.1)
class InputModule(AbstractInput): """ A sensor support class that measures the SHT2x's humidity and temperature and calculates the dew point """ def __init__(self, input_dev, testing=False): super(InputModule, self).__init__() self.logger = logging.getLogger("mycodo.inputs.sht2x") if not testing: from smbus2 import SMBus self.logger = logging.getLogger( "mycodo.sht2x_{id}".format(id=input_dev.unique_id.split('-')[0])) self.device_measurements = db_retrieve_table_daemon( DeviceMeasurements).filter( DeviceMeasurements.device_id == input_dev.unique_id) self.i2c_address = int(str(input_dev.i2c_location), 16) self.i2c_bus = input_dev.i2c_bus self.sht2x = SMBus(self.i2c_bus) def get_measurement(self): """ Gets the humidity and temperature """ return_dict = measurements_dict.copy() for _ in range(2): try: # Send temperature measurement command # 0xF3(243) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF3) time.sleep(0.5) # Read data back, 2 bytes # Temp MSB, Temp LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) temperature = -46.85 + (((data0 * 256 + data1) * 175.72) / 65536.0) # Send humidity measurement command # 0xF5(245) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF5) time.sleep(0.5) # Read data back, 2 bytes # Humidity MSB, Humidity LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) humidity = -6 + (((data0 * 256 + data1) * 125.0) / 65536.0) if self.is_enabled(0): return_dict[0]['value'] = temperature if self.is_enabled(1): return_dict[1]['value'] = humidity if (self.is_enabled(2) and self.is_enabled(0) and self.is_enabled(1)): return_dict[2]['value'] = calculate_dewpoint( return_dict[0]['value'], return_dict[1]['value']) if (self.is_enabled(3) and self.is_enabled(0) and self.is_enabled(1)): return_dict[3]['value'] = calculate_vapor_pressure_deficit( return_dict[0]['value'], return_dict[1]['value']) return return_dict except Exception as e: self.logger.exception( "Exception when taking a reading: {err}".format(err=e)) # Send soft reset and try a second read self.sht2x.write_byte(self.i2c_address, 0xFE) time.sleep(0.1)
class i2c_device: # Bit masks. bit0 = 0x01 bit1 = 0x02 bit2 = 0x04 bit3 = 0x08 bit4 = 0x10 bit5 = 0x20 bit6 = 0x40 bit7 = 0x80 def __init__(self, address=None, bus=None): self.address = address # "address" is the device address on the i2c bus. self.bus = bus self.DEBUG = 0 if self.bus == None: self.bus = DEFAULT_I2C_BUS # "bus" is the Raspberry Pi external i2c bus, where the MCP23017 is connected. # This may vary accross different Raspberry Pi models. 0 is used by the # original Raspbery Pi model B (256 MB memory, 26-pin GPIO connector). # 1 is used by recent Raspberry Pi devices. self.device = SMBus(self.bus) return def bus_reset(self): '''Caution: bus reset is a general call operation. It is not device-specific. All devices on the bus are affected. In systems with multiple i2c busses, only one bus (the bus associated with this device) is reset.''' self.device.write_byte(0, 6) return def wbyte_only(self, value): # Write a single byte to device, without any register address. self.device.write_byte(self.address, value) def rbyte_only(self): # Read a single byte from device, without any register address. return self.device.read_byte(self.address) def wbyte(self, reg, value): # Write a single byte <value> to register <reg>. if self.DEBUG >= 32: sys.stdout.write( ' write x{:02X} to chip x{:02X} register {}\n'.format( value, self.address, reg)) sys.flush() self.device.write_byte_data(self.address, reg, value) return def rbyte(self, reg): # Read one byte from register <reg>. return self.device.read_byte_data(self.address, reg) def wword(self, reg, value): '''Write the integer <value> (two bytes) to register <reg>.''' if byte_swap: value = ((value & 0xff) << 8) | ((value >> 8) & 0xff) self.device.write_word_data(self.address, reg, value) return def rword(self, reg): value = self.device.read_word_data(self.address, reg) if byte_swap: value = ((value & 0xff) << 8) | ((value >> 8) & 0xff) return value
from smbus2 import SMBus import time bus = SMBus(0) time.sleep(1) while True: counter = 0 id = "" ok = True while len(id) < 8: #while True: try: start = time.time() print("reading...") b = bus.read_byte(0x41) end = time.time() print(end-start) print("read", chr(b)) if end-start > 1: print("set ok to true") ok = True if ok: id += chr(b) except Exception as e: print(e) ok = False id="" continue #print("resetting counter")
class InputModule(AbstractInput): """ A sensor support class that measures the SHT2x's humidity and temperature and calculates the dew point """ def __init__(self, input_dev, testing=False): super(InputModule, self).__init__(input_dev, testing=testing, name=__name__) if not testing: self.initialize_input() def initialize_input(self): from smbus2 import SMBus self.i2c_address = int(str(self.input_dev.i2c_location), 16) self.sht2x = SMBus(self.input_dev.i2c_bus) def get_measurement(self): """ Gets the humidity and temperature """ if not self.sht2x: self.logger.error("Input not set up") return self.return_dict = copy.deepcopy(measurements_dict) for _ in range(2): try: # Send temperature measurement command # 0xF3(243) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF3) time.sleep(0.5) # Read data back, 2 bytes # Temp MSB, Temp LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) temperature = -46.85 + (( (data0 * 256 + data1) * 175.72) / 65536.0) # Send humidity measurement command # 0xF5(245) NO HOLD master self.sht2x.write_byte(self.i2c_address, 0xF5) time.sleep(0.5) # Read data back, 2 bytes # Humidity MSB, Humidity LSB data0 = self.sht2x.read_byte(self.i2c_address) data1 = self.sht2x.read_byte(self.i2c_address) humidity = -6 + (((data0 * 256 + data1) * 125.0) / 65536.0) if self.is_enabled(0): self.value_set(0, temperature) if self.is_enabled(1): self.value_set(1, humidity) if self.is_enabled(2) and self.is_enabled( 0) and self.is_enabled(1): self.value_set( 2, calculate_dewpoint(self.value_get(0), self.value_get(1))) if self.is_enabled(3) and self.is_enabled( 0) and self.is_enabled(1): self.value_set( 3, calculate_vapor_pressure_deficit( self.value_get(0), self.value_get(1))) return self.return_dict except Exception as e: self.logger.exception( "Exception when taking a reading: {err}".format(err=e)) # Send soft reset and try a second read self.sht2x.write_byte(self.i2c_address, 0xFE) time.sleep(0.1)
class EPS(Device): BUS_NAME = '/dev/i2c-1' ADDRESS = 0x57 def __init__(self): super().__init__("EPS") self.bus = SMBus() def is_open(self) -> bool: return self.bus.fd is not None def write_i2c_block_response(self, register: EPSRegister, data) -> bytes or None: if type(register) != EPSRegister: return self.write_i2c_block_data(register, data) return self.read_byte() def write_byte_response(self, register: EPSRegister, value) -> bytes or None: if type(register) != EPSRegister: return self.write_byte_data(register, value) return self.read_byte() def read_byte_data(self, register: EPSRegister) -> bytes or None: if type(register) != EPSRegister: return self.bus.open(self.BUS_NAME) next_byte = self.bus.read_byte_data(self.ADDRESS, register.value) self.bus.close() return next_byte def read_byte(self) -> bytes or None: self.bus.open(self.BUS_NAME) next_byte = self.bus.read_byte(self.ADDRESS) self.bus.close() return next_byte def write_i2c_block_data(self, register: EPSRegister, data): if type(register) != EPSRegister: return self.bus.open(self.BUS_NAME) self.bus.write_i2c_block_data(self.ADDRESS, register.value, data) self.bus.close() def write_byte_data(self, register: EPSRegister, value): if type(register) != EPSRegister: return self.bus.open(self.BUS_NAME) self.bus.write_byte_data(self.ADDRESS, register.value, value) self.bus.close() def functional(self): raise NotImplementedError def reset(self): raise NotImplementedError def disable(self): raise NotImplementedError def enable(self): raise NotImplementedError
class I2CBus(AbstractBus): """Initialize the I2C hardware driver and represent as bus object.""" type = BusType.I2C frequency = 100000 def start(self): """ """ # Todo: Improve error handling. try: if self.platform_info.vendor == self.platform_info.MICROPYTHON.Vanilla: from machine import I2C self.adapter = I2C(self.number, sda=Pin(int(self.pins['sda'][1:])), scl=Pin(int(self.pins['scl'][1:])), freq=self.frequency) elif self.platform_info.vendor == self.platform_info.MICROPYTHON.Pycom: from machine import I2C self.adapter = I2C(self.number, mode=I2C.MASTER, pins=(self.pins['sda'], self.pins['scl']), baudrate=self.frequency) elif self.platform_info.vendor == self.platform_info.MICROPYTHON.Odroid: from smbus2 import SMBus self.adapter = SMBus(self.number) elif self.platform_info.vendor == self.platform_info.MICROPYTHON.RaspberryPi: import board import busio def i2c_add_bus(busnum, scl, sda): """ Register more I2C buses with Adafruit Blinka. Make Adafruit Blinka learn another I2C bus. Please make sure you define it within /boot/config.txt like:: dtoverlay=i2c-gpio,bus=3,i2c_gpio_delay_us=1,i2c_gpio_sda=26,i2c_gpio_scl=20 """ # Uncache this module, otherwise monkeypatching will fail on subsequent calls. import sys try: del sys.modules['microcontroller.pin'] except: pass # Monkeypatch "board.pin.i2cPorts". i2c_port = (busnum, scl, sda) if i2c_port not in board.pin.i2cPorts: board.pin.i2cPorts += (i2c_port, ) pin_scl = self.pins['scl'] pin_sda = self.pins['sda'] # When I2C port pins are defined as Integers, register them first. if isinstance(pin_scl, int): i2c_add_bus(self.number, pin_scl, pin_sda) SCL = board.pin.Pin(pin_scl) SDA = board.pin.Pin(pin_sda) # When I2C port pins are defined as Strings and start with "board.", # they are probably already Pin aliases of Adafruit Blinka. elif isinstance(pin_scl, str) and pin_scl.startswith('board.'): SCL = eval(pin_scl) SDA = eval(pin_sda) self.adapter = busio.I2C(SCL, SDA) else: raise NotImplementedError( 'I2C bus is not implemented on this platform') self.just_started = True if not self.platform_info.vendor == self.platform_info.MICROPYTHON.Odroid: self.scan_devices() if self.platform_info.vendor == self.platform_info.MICROPYTHON.Odroid: self.devices = self.scan_devices_smbus2() log.info("Scan I2C bus via smbus2 for devices...") log.info("Found {} I2C devices: {}.".format( len(self.devices), self.devices)) self.ready = True except Exception as ex: #log.exc(ex, 'I2C hardware driver failed') raise def scan_devices(self): log.info('Scan I2C with id={} bus for devices...'.format(self.number)) self.devices = self.adapter.scan() # i2c.readfrom(0x76, 5) log.info("Found {} I2C devices: {}".format(len(self.devices), self.devices)) def scan_devices_smbus2(self, start=0x03, end=0x78): try: list = [] for i in range(start, end): val = 1 try: self.adapter.read_byte(i) except OSError as e: val = e.args[0] finally: if val != 5: # No device if val == 1: res = "Available" elif val == 16: res = "Busy" elif val == 110: res = "Timeout" else: res = "Error code: " + str(val) # print(hex(i) + " -> " + res) if res == 'Available': # print(i) list.append(i) return list except Exception as exp: log.exc(exp, 'scan smbus2 failed') def power_on(self): """ Turn on the I2C peripheral after power off. """ # Don't reinitialize device if power on just occurred through initial driver setup. if self.just_started: self.just_started = False return # uPy doesn't have deinit so it doesn't need init if self.platform_info.vendor == self.platform_info.MICROPYTHON.Pycom: from machine import I2C self.adapter.init(mode=I2C.MASTER, baudrate=self.frequency) def power_off(self): """ Turn off the I2C peripheral. https://docs.pycom.io/firmwareapi/pycom/machine/i2c.html """ log.info('Turning off I2C bus {}'.format(self.name)) if self.platform_info.vendor == self.platform_info.MICROPYTHON.Pycom: self.adapter.deinit()
user_input = 1 payload = 0 response = 0 other_response = 0 bomba2 = 7 bus = SMBus(1) wiringpi.wiringPiSetup() wiringpi.pinMode(bomba2, wiringpi.OUTPUT) while (user_input != 0): user_input = int(input('Qual ação deseja realizar? ')) bus.write_byte(slave_addr, user_input) sleep(0.2) response = bus.read_byte(slave_addr) print(INPUT[user_input], response) if (user_input == 9): if (response == 10): payload = 3 bus.write_byte(slave_addr, payload) sleep(1) other_response = bus.read_byte(slave_addr) while (other_response1 < 20): i = 0 while i < 20: bus.write_byte(slave_addr, payload)
class UpbeatLabs_MCP39F521(object): """Class for communicating with an MCP39F521 device like Dr. Wattson using the python smbus library.""" class Error_code(Enum): SUCCESS = 0 ERROR_INCORRECT_HEADER = 1 ERROR_CHECKSUM_FAIL = 2 ERROR_UNEXPECTED_RESPONSE = 3 ERROR_INSUFFICIENT_ARRAY_SIZE = 4 ERROR_CHECKSUM_MISMATCH = 5 ERROR_SET_VALUE_MISMATCH = 6 ERROR_VALUE_OUT_OF_BOUNDS = 7 class Event_config(Enum): EVENT_OVERCUR_TST = 0 EVENT_OVERPOW_TST = 1 EVENT_VSAG_TST = 2 EVENT_VSUR_TST = 3 EVENT_OVERCUR_LA = 4 EVENT_OVERPOW_LA = 5 EVENT_VSAG_LA = 6 EVENT_VSUR_LA = 7 EVENT_VSAG_CL = 8 EVENT_VSUR_CL = 9 EVENT_OVERPOW_CL = 10 EVENT_OVERCUR_CL = 11 EVENT_MANUAL = 14 EVENT_VSAG_PIN = 16 EVENT_VSURGE_PIN = 17 EVENT_OVERCUR_PIN = 18 EVENT_OVERPOW_PIN = 19 class System_status(Enum): SYSTEM_VSAG = 0 SYSTEM_VSURGE = 1 SYSTEM_OVERCUR = 2 SYSTEM_OVERPOW = 3 SYSTEM_SIGN_PA = 4 SYSTEM_SIGN_PR = 5 SYSTEM_EVENT = 10 class calibration_config(Enum): CALIBRATION_CONFIG_4A = 0 CALIBRATION_CONFIG_10A = 1 # 30 ohm burden resistor x2 CALIBRATION_CONFIG_15A = 2 # 20 ohm burden resistor x2 class __Response_code(Enum): RESPONSE_ACK = 0x06 RESPONSE_NAK = 0x15 RESPONSE_CSFAIL = 0x51 class __Command_code(Enum): COMMAND_REGISTER_READ_N_BYTES = 0x4e COMMAND_REGISTER_WRITE_N_BYTES = 0x4d COMMAND_SET_ADDRESS_POINTER = 0x41 COMMAND_SAVE_TO_FLASH = 0x53 COMMAND_PAGE_READ_EEPROM = 0x42 COMMAND_PAGE_WRITE_EEPROM = 0x50 COMMAND_BULK_ERASE_EEPROM = 0x4f COMMAND_AUTO_CALIBRATE_GAIN = 0x5a COMMAND_AUTO_CALIBRATE_REACTIVE_GAIN = 0x7a COMMAND_AUTO_CALIBRATE_FREQUENCY = 0x76 ## There is a bug in current MCP39F511/521 where energy accumulation ## values are off if the energy accumulation interval is ## anything but 2. This applies the workaround for that problem. ## To be removed for chips that have the issue fixed. ## XXX : TODO def __init__(self, address=MCP39F521_I2CADDR, busnum=DEFAULT_BUSNUM): """Create an instance of the MCP39F521 device at the specified address on the specified I2C bus number.""" self._address = address self._bus = SMBus(busnum) self._logger = logging.getLogger( 'DrWattson.UpbeatLabs_MCP39F521.Bus.{0}.Address.{1:#0X}'.format( busnum, address)) self._energy_accum_correction_factor = 1 (retVal, enabled) = self.isEnergyAccumulationEnabled() if (retVal == self.Error_code.SUCCESS.value and enabled): (retVal, accumIntervalReg) = self.readAccumulationIntervalRegister() self._energy_accum_correction_factor = (accumIntervalReg - 2) ## Get energy related data from the module ## ## Parameters: ## UpbeatLabs_MCP39F521_Data (output) - Metering data ## def readEnergyData(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x02, 28) data = UpbeatLabs_MCP39F521_Data() if (retVal == self.Error_code.SUCCESS.value): data.systemStatus = (buf[3] << 8 | buf[2]) data.systemVersion = (buf[5] << 8 | buf[4]) data.voltageRMS = (buf[7] << 8 | buf[6]) / 10.0 data.lineFrequency = (buf[9] << 8 | buf[8]) / 1000.0 data.analogInputVoltage = (buf[11] << 8 | buf[10]) / 1023.0 * 3.3 pfRaw = buf[13] << 8 | buf[12] f = ((pfRaw & 0x8000) >> 15) * -1.0 for ch in range(14, 3, -1): f += ((pfRaw & (1 << ch)) >> ch) * 1.0 / (1 << (15 - ch)) data.powerFactor = f data.currentRMS = (buf[17] << 24 | buf[16] << 16 | buf[15] << 8 | buf[14]) / 10000.0 data.activePower = (buf[21] << 24 | buf[20] << 16 | buf[19] << 8 | buf[18]) / 100.0 data.reactivePower = (buf[25] << 24 | buf[24] << 16 | buf[23] << 8 | buf[22]) / 100.0 data.apparentPower = (buf[29] << 24 | buf[28] << 16 | buf[27] << 8 | buf[26]) / 100.0 return (retVal, data) ## Get energy accumulator data from the module ## ## Parameters: ## UpbeatLabs_MCP39F521_AccumData (output) - accumulator data for energy ## Notes: ## On Arduino cannot read more than 32 bytes on I2C ## Let's just stick to that limit! ## Splitting out activeEnergyImport, activeEnergyExport and ## reactiveEnergyImport, reactiveEnergyExport into two calls ## as the total is 32+3 = 35 bytes otherwise. def readEnergyAccumData(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x1e, 16) data = UpbeatLabs_MCP39F521_AccumData() if (retVal == self.Error_code.SUCCESS.value): if (self._energy_accum_correction_factor == -1): data.activeEnergyImport = ( ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 | (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 | (buf[3]) << 8 | buf[2]) / 2) / 1000.0 data.activeEnergyExport = ( ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 | (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 | (buf[11]) << 8 | buf[10]) / 2) / 1000.0 else: data.activeEnergyImport = ( ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 | (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 | (buf[3]) << 8 | buf[2]) * (1 << self._energy_accum_correction_factor)) / 1000.0 data.activeEnergyExport = ( ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 | (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 | (buf[11]) << 8 | buf[10]) * (1 << self._energy_accum_correction_factor)) / 1000.0 time.sleep(0.05) (retVal, buf) = self.__registerReadNBytes(0x00, 0x2e, 16) if (retVal == self.Error_code.SUCCESS.value): if (self._energy_accum_correction_factor == -1): data.reactiveEnergyImport = ( ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 | (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 | (buf[3]) << 8 | buf[2]) / 2) / 1000.0 data.reactiveEnergyExport = ( ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 | (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 | (buf[11]) << 8 | buf[10]) / 2) / 1000.0 else: data.reactiveEnergyImport = ( ((buf[9]) << 56 | (buf[8]) << 48 | (buf[7]) << 40 | (buf[6]) << 32 | (buf[5]) << 24 | (buf[4]) << 16 | (buf[3]) << 8 | buf[2]) * (1 << self._energy_accum_correction_factor)) / 1000.0 data.reactiveEnergyExport = ( ((buf[17]) << 56 | (buf[16]) << 48 | (buf[15]) << 40 | (buf[14]) << 32 | (buf[13]) << 24 | (buf[12]) << 16 | (buf[11]) << 8 | buf[10]) * (1 << self._energy_accum_correction_factor)) / 1000.0 return (retVal, data) # Event control methods ## Reads the event configuration and returns the 32-bit bit map. ## Use the event_config enum to read bits of interest, without ## worrying about the bit position and structure of the ## event config register ## ## For example, bitRead(eventConfigRegisterValue, EVENT_VSAG_PIN) ## to see if event notification for VSAG events is turned on def readEventConfigRegister(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x7e, 4) configRegister = 0 if (retVal == self.Error_code.SUCCESS.value): configRegister = buf[5] << 24 | buf[4] << 16 | buf[3] << 8 | buf[2] return (retVal, configRegister) ## Set the event configuration register to the appropriate value ## ## First, read the existing register value. Then, set (or clear) appropriate ## bits using the event_config enum for assitance. Lastly, set the ## new value back in the register. ## ## For example, bitSet(eventConfigRegisterValue, EVENT_VSAG_PIN) ## to turn on the event notification for VSAG events ## or bitClear(eventConfigRegisterValue, EVENT_VSAG_PIN) def setEventConfigurationRegister(self, value): byteArray = [] byteArray.append(value & 0xFF) byteArray.append((value >> 8) & 0xFF) byteArray.append((value >> 16) & 0xFF) byteArray.append((value >> 24) & 0xFF) retVal = self.__registerWriteNBytes(0x00, 0x7e, 4, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal (retVal, readArray) = self.__registerReadNBytes(0x00, 0x7e, 4) if (retVal == self.Error_code.SUCCESS.value): readValue = readArray[5] << 24 | readArray[4] << 16 | readArray[ 3] << 8 | readArray[2] if (readValue != value): return self.Error_code.ERROR_SET_VALUE_MISMATCH.value return self.Error_code.SUCCESS.value ## Read the event flag limits that have been set for the various events. ## For example, the voltage sag limit sets the voltage value below which ## the VSAG event is triggered ## ## See UpbeatLabs_MCP39F521_EventFlagLimits for more information about ## various limits def readEventFlagLimitRegisters(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0xA0, 12) data = UpbeatLabs_MCP39F521_EventFlagLimits() if (retVal == self.Error_code.SUCCESS.value): data.voltageSagLimit = (buf[3] << 8 | buf[2]) data.voltageSurgeLimit = (buf[5] << 8 | buf[4]) data.overCurrentLimit = (buf[9] << 24 | buf[8] << 16 | buf[7] << 8 | buf[6]) data.overPowerLimit = (buf[13] << 24 | buf[12] << 16 | buf[11] << 8 | buf[10]) return (retVal, data) ## Write the event flag limits for the various events. ## For example, the voltage sag limit sets the voltage value below which ## the VSAG event is triggered ## ## See UpbeatLabs_MCP39F521_EventFlagLimits for more information about ## various limits def writeEventFlagLimitRegisters(self, input): byteArray = [] byteArray.append(input.voltageSagLimit & 0xFF) byteArray.append((input.voltageSagLimit >> 8) & 0xFF) byteArray.append(input.voltageSurgeLimit & 0xFF) byteArray.append((input.voltageSurgeLimit >> 8) & 0xFF) byteArray.append(input.overCurrentLimit & 0xFF) byteArray.append((input.overCurrentLimit >> 8) & 0xFF) byteArray.append((input.overCurrentLimit >> 16) & 0xFF) byteArray.append((input.overCurrentLimit >> 24) & 0xFF) byteArray.append(input.overPowerLimit & 0xFF) byteArray.append((input.overPowerLimit >> 8) & 0xFF) byteArray.append((input.overPowerLimit >> 16) & 0xFF) byteArray.append((input.overPowerLimit >> 24) & 0xFF) retVal = self.__registerWriteNBytes(0x00, 0xA0, 12, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal (retVal, eventFlagLimitsData) = self.readEventFlagLimitRegisters() if (retVal == self.Error_code.SUCCESS.value): ## Verify read values with input values if (eventFlagLimitsData.voltageSagLimit != input.voltageSagLimit or eventFlagLimitsData.voltageSurgeLimit != input.voltageSurgeLimit or eventFlagLimitsData.overCurrentLimit != input.overCurrentLimit or eventFlagLimitsData.overPowerLimit != input.overPowerLimit): return self.Error_code.ERROR_SET_VALUE_MISMATCH.value return retVal # EEPROM methods ## Bulk erase all pages of the EEPROM memory def bulkEraseEEPROM(self): return self.__issueAckNackCommand( self.__Command_code.COMMAND_BULK_ERASE_EEPROM.value) def pageReadEEPROM(self, pageNum): """Implementation of pageReadEEPROM """ data = [ 0xa5, 0x05, self.__Command_code.COMMAND_PAGE_READ_EEPROM.value, pageNum ] checksum = 0 for x in data: checksum += x data.append(checksum % 256) write = i2c_msg.write(self._address, data) self._bus.i2c_rdwr(write) time.sleep(0.05) ## ## Read the specified length of data - ACK, Num Bytes, EEPROM Page Data, Checksum ## -> 1 + 1 + 16 + 1 = 19 bytes of data ## read = i2c_msg.read(self._address, 19) self._bus.i2c_rdwr(read) buf = [] buf.extend(read) return (self.__checkHeaderAndChecksum(16, buf), buf[2:-1]) def pageWriteEEPROM(self, pageNum, byteArray): """Implementation of pageWriteEEPROM """ if (len(byteArray) != 16): return self.Error_code.ERROR_INSUFFICIENT_ARRAY_SIZE.value data = [ 0xa5, 21, self.__Command_code.COMMAND_PAGE_WRITE_EEPROM.value, pageNum ] # Data here... data.extend(byteArray) checksum = 0 for x in data: checksum += x data.append(checksum % 256) write = i2c_msg.write(self._address, data) self._bus.i2c_rdwr(write) time.sleep(0.05) header = self._bus.read_byte(self._address) self._logger.debug(header) return self.__checkHeader(header) # Energy Accumulation methods ## This method is used to turn on/off energy accumulation. ## When it is turned on, the data read from the module ## in UpbeatLabs_MCP39F521_AccumData represents the ## accumulated energy data over the no load threshold ## (defaults to 1w). Therefore any energy over 1w ## gets accumulated over time. ## There is a bug in current MCP39F511/521 where energy accumulation ## values are off if the energy accumulation interval is ## anything but 2. This applies the workaround for that problem. ## To be removed for chips that have the issue fixed. def enableEnergyAccumulation(self, enable): ## First, note the accumulation interval. If it is anything ## other than the default (2), note the correction ## factor that has to be applied to the energy ## accumulation. (retVal, accumIntervalReg) = self.readAccumulationIntervalRegister() self._energy_accum_correction_factor = (accumIntervalReg - 2) byteArray = [enable, 0] ## write register retVal = self.__registerWriteNBytes(0x00, 0xDC, 2, byteArray) return retVal def isEnergyAccumulationEnabled(self): (retVal, readArray) = self.__registerReadNBytes(0x00, 0xDC, 5) enabled = False if (retVal == self.Error_code.SUCCESS.value): enabled = readArray[2] return (retVal, enabled) # <---- End Energy Accumulation methods # START --- WARNING!!! WARNING!!! WARNING!!! # Advanced methods for calibration, etc # WARNING!!!! Use with extreme caution! These can render your Dr. Wattson # uncalibrated. Only use if you know what you are doing! ## Read the contents of the calibration registers ## Results returned in UpbeatLabs_MCP39F521_CalibrationData object def readCalibrationRegisters(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x5e, 28) data = UpbeatLabs_MCP39F521_CalibrationData() if (retVal == self.Error_code.SUCCESS.value): data.calibrationRegisterDelimiter = (buf[3] << 8 | buf[2]) data.gainCurrentRMS = (buf[5] << 8 | buf[4]) data.gainVoltageRMS = (buf[7] << 8 | buf[6]) data.gainActivePower = (buf[9] << 8 | buf[8]) data.gainReactivePower = (buf[11] << 8 | buf[10]) data.offsetCurrentRMS = (buf[15] << 24 | buf[14] << 16 | buf[13] << 8 | buf[12]) data.offsetActivePower = (buf[19] << 24 | buf[18] << 16 | buf[17] << 8 | buf[16]) data.offsetReactivePower = (buf[23] << 24 | buf[22] << 16 | buf[21] << 8 | buf[20]) data.dcOffsetCurrent = (buf[25] << 8 | buf[24]) data.phaseCompensation = (buf[27] << 8 | buf[26]) data.apparentPowerDivisor = (buf[29] << 8 | buf[28]) return (retVal, data) ## This method writes the current, voltage, active power and reactive power gains directly to ## the MCP39F521 registers. Use this if you know what the appropriate gains are to be for ## your particular metering range and design. Typically, these are not to be changed unless ## you are performing your own calibration, and even so, it is better to use the ## auto-calibration methods instead. This is one big gun to shoot yourself, be warned! def writeGains(self, gainCurrentRMS, gainVoltageRMS, gainActivePower, gainReactivePower): byteArray = [] byteArray.append(gainCurrentRMS & 0xFF) byteArray.append((gainCurrentRMS >> 8) & 0xFF) byteArray.append(gainVoltageRMS & 0xFF) byteArray.append((gainVoltageRMS >> 8) & 0xFF) byteArray.append(gainActivePower & 0xFF) byteArray.append((gainActivePower >> 8) & 0xFF) byteArray.append(gainReactivePower & 0xFF) byteArray.append((gainReactivePower >> 8) & 0xFF) retVal = self.__registerWriteNBytes(0x00, 0x60, 8, byteArray) return retVal ## Read the system config register, which is a 32-bit bit map. ## The system config register is used to set setting like ## PGA gains for current and voltage channels, etc ## You will typically not be changing these unless you are ## performing a calibration. def readSystemConfigRegister(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x7a, 4) value = 0 if (retVal == self.Error_code.SUCCESS.value): value = buf[5] << 24 | buf[4] << 16 | buf[3] << 8 | buf[2] return (retVal, value) ## Set the system config register, which is a 32-bit bit map. ## The system config register is used to set setting like ## PGA gains for current and voltage channels, etc ## You will typically not be changing these unless you are ## performing a calibration. Do not use unless you know what ## you are doing! This is one big gun to shoot yourself, be warned! def setSystemConfigurationRegister(self, value): retVal = 0 byteArray = [0] * 4 byteArray[0] = value & 0xFF byteArray[1] = (value >> 8) & 0xFF byteArray[2] = (value >> 16) & 0xFF byteArray[3] = (value >> 24) & 0xFF # print byteArray retVal = self.__registerWriteNBytes(0x00, 0x7a, 4, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal time.sleep(0.05) (retVal, readArray) = self.__registerReadNBytes(0x00, 0x7a, 4) readValue = ((readArray[5]) << 24 | (readArray[4]) << 16 | (readArray[3]) << 8 | readArray[2]) if (readValue != value): return self.Error_code.ERROR_SET_VALUE_MISMATCH.value return self.Error_code.SUCCESS.value ## Read the accumlation interval register, which represents N in 2^N ## number of line cycles to be used for a single computation. ## You will not be modifying this unless you are performing a ## calibration. def readAccumulationIntervalRegister(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x9e, 2) value = 0 if (retVal == self.Error_code.SUCCESS.value): value = buf[3] << 8 | buf[2] return (retVal, value) ## Set the accumlation interval register, which represents N in 2^N ## number of line cycles to be used for a single computation. ## You will not be modifying this unless you are performing a ## calibration. Use with caution!! def setAccumulationIntervalRegister(self, value): retVal = 0 byteArray = [0] * 2 byteArray[0] = value & 0xFF byteArray[1] = (value >> 8) & 0xFF retVal = self.__registerWriteNBytes(0x00, 0x9e, 2, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal time.sleep(0.05) (retVal, readArray) = self.__registerReadNBytes(0x00, 0x9e, 2) readValue = ((readArray[3]) << 8 | readArray[2]) if (readValue != value): return self.Error_code.ERROR_SET_VALUE_MISMATCH.value return self.Error_code.SUCCESS.value ## Read the design config registers into the UpbeatLabs_MCP39F521_DesignConfigData struct. ## See class for more details. These are used to set the appropriate calibration values for ## calibrating your module. def readDesignConfigurationRegisters(self): (retVal, buf) = self.__registerReadNBytes(0x00, 0x82, 20) data = UpbeatLabs_MCP39F521_DesignConfigData() if (retVal == self.Error_code.SUCCESS.value): data.rangeVoltage = buf[2] data.rangeCurrent = buf[3] data.rangePower = buf[4] data.rangeUnimplemented = buf[5] data.calibrationCurrent = (buf[9] << 24 | buf[8] << 16 | buf[7] << 8 | buf[6]) data.calibrationVoltage = ((buf[11] << 8) | buf[10]) data.calibrationPowerActive = (buf[15] << 24 | buf[14] << 16 | buf[13] << 8 | buf[12]) data.calibrationPowerReactive = (buf[19] << 24 | buf[18] << 16 | buf[17] << 8 | buf[16]) data.lineFrequencyRef = ((buf[21] << 8) | buf[20]) return (retVal, data) ## Write the design config registers. See UpbeatLabs_MCP39F521_DesignConfigData ## struct for more details. These are used to set the appropriate calibration values for ## calibrating your module. Use this method only if you know what you are doing! ## This is one big gun to shoot yourself, be warned! def writeDesignConfigRegisters(self, data): byteArray = [] * 20 ## range byteArray[0] = data.rangeVoltage byteArray[1] = data.rangeCurrent byteArray[2] = data.rangePower byteArray[3] = data.rangeUnimplemented ## calibration current byteArray[4] = data.calibrationCurrent & 0xFF byteArray[5] = (data.calibrationCurrent >> 8) & 0xFF byteArray[6] = (data.calibrationCurrent >> 16) & 0xFF byteArray[7] = (data.calibrationCurrent >> 24) & 0xFF ## calibration voltage byteArray[8] = data.calibrationVoltage & 0xFF byteArray[9] = (data.calibrationVoltage >> 8) & 0xFF ## calibration power active byteArray[10] = data.calibrationPowerActive & 0xFF byteArray[11] = (data.calibrationPowerActive >> 8) & 0xFF byteArray[12] = (data.calibrationPowerActive >> 16) & 0xFF byteArray[13] = (data.calibrationPowerActive >> 24) & 0xFF ## calibration power reactive byteArray[14] = data.calibrationPowerReactive & 0xFF byteArray[15] = (data.calibrationPowerReactive >> 8) & 0xFF byteArray[16] = (data.calibrationPowerReactive >> 16) & 0xFF byteArray[17] = (data.calibrationPowerReactive >> 24) & 0xFF ## line frequency ref byteArray[18] = data.lineFrequencyRef & 0xFF byteArray[19] = (data.lineFrequencyRef >> 8) & 0xFF retVal = self.__registerWriteNBytes(0x00, 0x82, 20, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal time.sleep(0.05) ## Read the values to verify write (retVal, designConfigData) = self.readDesignConfigurationRegisters() if (retVal != self.Error_code.SUCCESS.value): return retVal ## Verify read values with input values if (designConfigData.rangeVoltage != data.rangeVoltage or designConfigData.rangeCurrent != data.rangeCurrent or designConfigData.rangePower != data.rangePower or designConfigData.calibrationCurrent != data.calibrationCurrent or designConfigData.calibrationVoltage != data.calibrationVoltage or designConfigData.calibrationPowerActive != data.calibrationPowerActive or designConfigData.calibrationPowerReactive != data.calibrationPowerReactive or designConfigData.lineFrequencyRef != data.lineFrequencyRef): return self.Error_code.ERROR_SET_VALUE_MISMATCH.value return self.Error_code.SUCCESS.value ## Write the phase compensation register. This will not be required unless ## you are manually writing calibration values yourself. Use with caution! def writePhaseCompensation(self, phaseCompensation): byteArray = [] * 2 ## Calibrating phase byteArray[0] = phaseCompensation byteArray[1] = 0 retVal = self.__registerWriteNBytes(0x00, 0x76, 2, byteArray) return retVal ## Read and set the ambient reference temperature when ## calibrating. This is used during calibration as one ## of the steps. Use with caution! def readAndSetTemperature(self): (retVal, byteArray) = __registerReadNBytes(0x00, 0x0a, 2) if (retVal != self.Error_code.SUCCESS.value): return retVal bytesWrite = [] * 2 bytesWrite[0] = byteArray[2] bytesWrite[1] = byteArray[3] retVal = self.__registerWriteNBytes(0x00, 0xcc, 2, bytesWrite) return retVal ## Invoke the "autoCalibrate Gain" command. Prior to this, ## other requisite steps need to be taken like setting ## the design config registers with the appropriate ## calibration values. Use only if you know what you are ## doing! This is one big gun to shoot yourself, be warned! def autoCalibrateGain(self): return self.__issueAckNackCommand( self.__Command_code.COMMAND_AUTO_CALIBRATE_GAIN.value) ## Invoke the "autoCalibrate Reactive Gain" command. Prior to this, ## other requisite steps need to be taken like setting ## the design config registers with the appropriate ## calibration values, and auto calibrating gain. ## Use only if you know what you are doing! ## This is one big gun to shoot yourself, be warned! def autoCalibrateReactiveGain(self): return self.__issueAckNackCommand( self.__Command_code.COMMAND_AUTO_CALIBRATE_REACTIVE_GAIN.value) ## Invoke the "autoCalibrate Line Frequency" command. Prior to this, ## other requisite calibration steps need to be taken like setting ## the appropriate design config registers. ## Use only if you know what you are doing! ## This is one big gun to shoot yourself, be warned! def autoCalibrateFrequency(self): return self.__issueAckNackCommand( self.__Command_code.COMMAND_AUTO_CALIBRATE_FREQUENCY.value) ## This method is used to calibrate the phase compensation ## when calibrating the module, as one of the steps during ## system calibration. Use only if you know what you are doing! ## This is one big gun to shoot yourself, be warned! def calibratePhase(self, pfExp): (retVal, byteArray) = self.__registerReadNBytes(0x00, 0x0c, 2) if (retVal != self.Error_code.SUCCESS.value): return retVal pfRaw = buf[13] << 8 | buf[12] f = ((pfRaw & 0x8000) >> 15) * -1.0 for ch in range(14, 3, -1): f += ((pfRaw & (1 << ch)) >> ch) * 1.0 / (1 << (15 - ch)) pfMeasured = f angleMeasured = acos(pfMeasured) angleExp = acos(pfExp) angleMeasuredDeg = angleMeasured * 180.0 / 3.14159 angleExpDeg = angleExp * 180.0 / 3.14159 phi = (angleMeasuredDeg - angleExpDeg) * 40.0 (retVal, byteArray) = self.__registerReadNBytes(0x00, 0x76, 2) if (retVal != self.Error_code.SUCCESS.value): return retVal # phase compensation is stored as an 8-bit 2's complement number # (in a 16 bit register) pcRaw = byteArray[2] if pcRaw > 127: pcRaw = pcRaw - 256 phaseComp = pcRaw phaseCompNew = phaseComp + phi # New value has to be between 127 and -128 and has to be converted # back to an 8 bit integer for transmission if (phaseCompNew > 127 or phaseCompNew < -128): retVal = self.Error_code.ERROR_VALUE_OUT_OF_BOUNDS.value else: ## Calibrating phase bytes = [0] * 2 # converting back to 8 bit unsigned integer representation of # two's complement value bytes[0] = phaseCompNew if (phaseCompNew >= 0) else (256 + phaseCompNew) bytes[1] = 0 retVal = self.__registerWriteNBytes(0x00, 0x76, 2, bytes) return retVal ## This method saves the contents of all calibration ## and configuration registers to flash. Use with caution! def saveToFlash(self): return self.__issueAckNackCommand( self.__Command_code.COMMAND_SAVE_TO_FLASH.value) # This will revert the MCP39F521 to its factory settings and # remove any calibration data. Use with extreme caution!!!! def factoryReset(self): byteArray = [0] * 2 byteArray[0] = 0xa5 byteArray[1] = 0xa5 retVal = self.__registerWriteNBytes(0x00, 0x5e, 2, byteArray) if (retVal != self.Error_code.SUCCESS.value): return retVal retVal = self.saveToFlash() return retVal ## This method will reset the calibration values to Dr. Wattson def resetCalibration(self, cc=calibration_config.CALIBRATION_CONFIG_4A.value): global calibConfig retVal = self.Error_code.SUCCESS.value retVal = self.setSystemConfigurationRegister( calibConfig[cc].systemConfig) # Channel 1 Gain 4, Channel 0 Gain 1 if (retVal != self.Error_code.SUCCESS.value): return retVal retVal = self.setAccumulationIntervalRegister( calibConfig[cc].accumInt) # Accumulation interval 5 if (retVal != self.Error_code.SUCCESS.value): return retVal ## We need to apply correction factor where accumulation interval is not 2; if (calibConfig[cc].accumInt > 2): self._energy_accum_correction_factor = (calibConfig[cc].accumInt - 2) retVal = self.writeDesignConfigRegisters( calibConfig[cc].designConfigData) if (retVal != self.Error_code.SUCCESS.value): return retVal retVal = self.writeGains(calibConfig[cc].gainCurrentRMS, calibConfig[cc].gainVoltageRMS, calibConfig[cc].gainActivePower, calibConfig[cc].gainReactivePower) if (retVal != self.Error_code.SUCCESS.value): return retVal retVal = self.writePhaseCompensation(calibConfig[cc].phaseCompensation) if (retVal != self.Error_code.SUCCESS.value): return retVal retVal = self.saveToFlash() if (retVal != self.Error_code.SUCCESS.value): return retVal return self.Error_code.SUCCESS.value # END --- WARNING!!! WARNING!!! WARNING!!! ## Bit manipulation convenience methods # Check to see if the kth bit is set in value n # (where k starts with 0 for the least significant bit def bitRead(self, n, k): return n & (1 << k) # Set the kth bit in value n # (where k starts with 0 for the least significant bit def bitSet(self, n, k): return n | (1 << k) # Clear the kth bit in value n # (where k starts with 0 for the least significant bit def bitClear(self, n, k): return n ^ (1 << k) ## Private methods --- ## Read the contents of the registers starting with the starting address, ## up to the number of bytes specified. def __registerReadNBytes(self, addressHigh, addressLow, numBytesToRead): """Implementation of RegisterReadNBytes """ data = [ 0xa5, 0x08, self.__Command_code.COMMAND_SET_ADDRESS_POINTER.value, addressHigh, addressLow, self.__Command_code.COMMAND_REGISTER_READ_N_BYTES.value, numBytesToRead ] checksum = 0 for x in data: checksum += x # Add checksum at the end data.append(checksum % 256) write = i2c_msg.write(self._address, data) self._bus.i2c_rdwr(write) time.sleep(0.05) read = i2c_msg.read(self._address, numBytesToRead + 3) self._bus.i2c_rdwr(read) buf = [] buf.extend(read) # print buf return (self.__checkHeaderAndChecksum(numBytesToRead, buf), buf) ## Write to the registers, starting from the starting address the number of bytes ## specified in the byteArray def __registerWriteNBytes(self, addressHigh, addressLow, numBytes, byteArray): """Implementation of registerWriteNBytes """ data = [ 0xa5, numBytes + 8, self.__Command_code.COMMAND_SET_ADDRESS_POINTER.value, addressHigh, addressLow, self.__Command_code.COMMAND_REGISTER_WRITE_N_BYTES.value, numBytes ] ## data here data.extend(byteArray) # print data ## compute and fill checksum as last element checksum = 0 for x in data: checksum += x data.append(checksum % 256) write = i2c_msg.write(self._address, data) self._bus.i2c_rdwr(write) time.sleep(0.05) header = self._bus.read_byte(self._address) self._logger.debug(header) return self.__checkHeader(header) ## Some commands are issued and just return an ACK (or NAK) ## This method factors out those types of commands ## and takes in as argument the specified command to issue. def __issueAckNackCommand(self, command): """Implementation of issueAckNackCommand """ # header, numBytes, command data = [0xa5, 0x04, command] checksum = 0 for x in data: checksum += x # Add checksum at the end data.append(checksum % 256) write = i2c_msg.write(self._address, data) self._bus.i2c_rdwr(write) time.sleep(0.05) ## Read the ack header = self._bus.read_byte(self._address) self._logger.debug(header) return self.__checkHeader(header) ## Convenience method to check the header and the checksum for the returned data. ## If all is good, this method should return SUCCESS def __checkHeaderAndChecksum(self, numBytesToRead, byteArray): """Implementation of checkHeaderAndChecksum """ checksumTotal = 0 header = byteArray[0] dataLen = byteArray[1] checksum = byteArray[numBytesToRead + 3 - 1] for i in range(0, numBytesToRead + 3 - 1): checksumTotal += byteArray[i] calculatedChecksum = checksumTotal % 256 error = self.Error_code.SUCCESS.value error = self.__checkHeader(header) if (calculatedChecksum != checksum): error = self.Error_code.ERROR_CHECKSUM_MISMATCH.value return error ## Convenience method to check the header of the response. ## If all is good, this will return SUCCESS def __checkHeader(self, header): """Implementation of checkHeader """ error = self.Error_code.SUCCESS.value if (header != self.__Response_code.RESPONSE_ACK.value): error = self.Error_code.ERROR_INCORRECT_HEADER.value if (header == self.__Response_code.RESPONSE_CSFAIL.value): error = self.Error_code.ERROR_CHECKSUM_FAIL.value return error
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)