def __init__(self, spi_bus, spi_device): """ Constructor """ self.__io = IO() self.__spi = SPI(spi_bus, spi_device, OPCN2.__SPI_MODE, OPCN2.__SPI_CLOCK)
def __init__(self, interface, spi_bus, spi_device): """ Constructor """ super().__init__(interface) self.__spi = SPI(spi_bus, spi_device, SPINDIRx1.__SPI_MODE, SPINDIRx1.__SPI_CLOCK)
def __init__(self, font): """ Constructor """ self.__font = font self.__device = InkyPHAT(self.COLOUR) self.__image = Image.new("P", (self.__device.WIDTH, self.__device.HEIGHT)) self.__drawing = ImageDraw.Draw(self.__image) m_width, m_height = self.__font.getsize("M") self.__text_width = self.__device.WIDTH // m_width self.__text_height = self.__device.HEIGHT // m_height + 1 self.__stop = None self.__render_timeout = Timeout(self.DRAW_TIME) # self.__spi = SPI(self.__SPI_BUS, self.__SPI_DEVICE, None, None) self.__spi = SPI(self.__SPI_BUS, self.__SPI_DEVICE, self.__SPI_MODE, self.__SPI_CLOCK)
class SPINDIRx1(NDIR): """ classdocs """ # ---------------------------------------------------------------------------------------------------------------- SAMPLE_INTERVAL = 1.0 # seconds between on-board sampling # ---------------------------------------------------------------------------------------------------------------- __LOCK_TIMEOUT = 4.0 # seconds __BOOT_DELAY = 3.500 # seconds to first sample available __PARAM_DELAY = 0.001 # seconds between SPI sessions __RESPONSE_ACK = 0x01 __RESPONSE_NACK = 0x02 __RESPONSE_BUSY = 0x03 __RESPONSE_NONE = (0x00, 0xff) __SPI_CLOCK = 488000 __SPI_MODE = 1 # ---------------------------------------------------------------------------------------------------------------- @classmethod def obtain_lock(cls): Lock.acquire(cls.__name__, SPINDIRx1.__LOCK_TIMEOUT) @classmethod def release_lock(cls): Lock.release(cls.__name__) @classmethod def get_sample_interval(cls): return cls.SAMPLE_INTERVAL # ---------------------------------------------------------------------------------------------------------------- @classmethod def boot_time(cls): return cls.__BOOT_DELAY # ---------------------------------------------------------------------------------------------------------------- def __init__(self, interface, spi_bus, spi_device): """ Constructor """ super().__init__(interface) self.__spi = SPI(spi_bus, spi_device, SPINDIRx1.__SPI_MODE, SPINDIRx1.__SPI_CLOCK) # ---------------------------------------------------------------------------------------------------------------- # NDIR implementation... def sample(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('sg') response = self._transact(cmd) cnc = Decode.float(response[0:4], '<') cnc_igl = Decode.float(response[4:8], '<') temp = Decode.float(response[8:12], '<') return NDIRDatum(temp, cnc, cnc_igl) finally: self.release_lock() def version(self): try: self.obtain_lock() # version ident... cmd = SPINDIRx1Cmd.find('vi') response = self._transact(cmd) id = ''.join([chr(byte) for byte in response]).strip() # version tag... cmd = SPINDIRx1Cmd.find('vt') response = self._transact(cmd) tag = ''.join([chr(byte) for byte in response]).strip() version = NDIRVersion(id, NDIRTag.construct_from_jdict(tag)) return version finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # barometric pressure... def pressure(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('sp') response = self._transact(cmd) p_a = Decode.float(response[0:4], '<') return round(p_a, 1) finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # status... def status(self): try: self.obtain_lock() # restart status... cmd = SPINDIRx1Cmd.find('ws') response = self._transact(cmd) watchdog_reset = bool(response) # input voltage... cmd = SPINDIRx1Cmd.find('iv') response = self._transact(cmd) pwr_in = Decode.float(response, '<') # uptime... cmd = SPINDIRx1Cmd.find('up') response = self._transact(cmd) seconds = Decode.unsigned_long(response, '<') status = NDIRStatus(watchdog_reset, pwr_in, NDIRUptime(seconds)) return status finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # calib... def store_calib(self, calib): try: self.obtain_lock() # identity... self._calib_w_unsigned_long(0, NDIRCalib.INDEX_NDIR_SERIAL, calib.ndir_serial) self._calib_w_unsigned_long(0, NDIRCalib.INDEX_BOARD_SERIAL, calib.board_serial) self._calib_w_unsigned_int(0, NDIRCalib.INDEX_SELECTED_RANGE, calib.selected_range) # common fields... self._calib_w_float(0, NDIRCalib.INDEX_LAMP_VOLTAGE, calib.lamp_voltage) self._calib_w_unsigned_int(0, NDIRCalib.INDEX_LAMP_PERIOD, calib.lamp_period) self._calib_w_unsigned_int(0, NDIRCalib.INDEX_SAMPLE_START, calib.sample_start) self._calib_w_unsigned_int(0, NDIRCalib.INDEX_SAMPLE_END, calib.sample_end) # range calibrations... self._store_range_calib(NDIRCalib.RANGE_IAQ, calib.range_iaq) self._store_range_calib(NDIRCalib.RANGE_SAFETY, calib.range_safety) self._store_range_calib(NDIRCalib.RANGE_COMBUSTION, calib.range_combustion) self._store_range_calib(NDIRCalib.RANGE_INDUSTRIAL, calib.range_industrial) self._store_range_calib(NDIRCalib.RANGE_CUSTOM, calib.range_custom) finally: self.release_lock() def _store_range_calib(self, rng, calib): # range check... if calib is None: self._calib_w_unsigned_int(rng, NDIRRangeCalib.INDEX_RANGE_IS_SET, 0) return self._calib_w_unsigned_int(rng, NDIRRangeCalib.INDEX_RANGE_IS_SET, 1) # range fields... self._calib_w_float(rng, NDIRRangeCalib.INDEX_ZERO, calib.zero) self._calib_w_float(rng, NDIRRangeCalib.INDEX_SPAN, calib.span) self._calib_w_float(rng, NDIRRangeCalib.INDEX_LINEAR_B, calib.linear_b) self._calib_w_float(rng, NDIRRangeCalib.INDEX_LINEAR_C, calib.linear_c) self._calib_w_float(rng, NDIRRangeCalib.INDEX_ALPHA_LOW, calib.alpha_low) self._calib_w_float(rng, NDIRRangeCalib.INDEX_ALPHA_HIGH, calib.alpha_high) self._calib_w_float(rng, NDIRRangeCalib.INDEX_BETA_A, calib.beta_a) self._calib_w_float(rng, NDIRRangeCalib.INDEX_BETA_O, calib.beta_o) self._calib_w_float(rng, NDIRRangeCalib.INDEX_T_CAL, calib.t_cal) def retrieve_calib(self): try: self.obtain_lock() # identity... ndir_serial = self._calib_r_unsigned_long( 0, NDIRCalib.INDEX_NDIR_SERIAL) board_serial = self._calib_r_unsigned_long( 0, NDIRCalib.INDEX_BOARD_SERIAL) selected_range = self._calib_r_unsigned_int( 0, NDIRCalib.INDEX_SELECTED_RANGE) # common fields... lamp_voltage = self._calib_r_float(0, NDIRCalib.INDEX_LAMP_VOLTAGE) lamp_period = self._calib_r_unsigned_int( 0, NDIRCalib.INDEX_LAMP_PERIOD) sample_start = self._calib_r_unsigned_int( 0, NDIRCalib.INDEX_SAMPLE_START) sample_end = self._calib_r_unsigned_int(0, NDIRCalib.INDEX_SAMPLE_END) # range calibrations... range_iaq = self._retrieve_range_calib(NDIRCalib.RANGE_IAQ) range_safety = self._retrieve_range_calib(NDIRCalib.RANGE_SAFETY) range_combustion = self._retrieve_range_calib( NDIRCalib.RANGE_COMBUSTION) range_industrial = self._retrieve_range_calib( NDIRCalib.RANGE_INDUSTRIAL) range_custom = self._retrieve_range_calib(NDIRCalib.RANGE_CUSTOM) return NDIRCalib(ndir_serial, board_serial, selected_range, lamp_voltage, lamp_period, sample_start, sample_end, range_iaq, range_safety, range_combustion, range_industrial, range_custom) finally: self.release_lock() def _retrieve_range_calib(self, rng): # range check... if not self._calib_r_unsigned_int(rng, NDIRRangeCalib.INDEX_RANGE_IS_SET): return None # range fields... zero = self._calib_r_float(rng, NDIRRangeCalib.INDEX_ZERO) span = self._calib_r_float(rng, NDIRRangeCalib.INDEX_SPAN) linear_b = self._calib_r_float(rng, NDIRRangeCalib.INDEX_LINEAR_B) linear_c = self._calib_r_float(rng, NDIRRangeCalib.INDEX_LINEAR_C) alpha_low = self._calib_r_float(rng, NDIRRangeCalib.INDEX_ALPHA_LOW) alpha_high = self._calib_r_float(rng, NDIRRangeCalib.INDEX_ALPHA_HIGH) beta_a = self._calib_r_float(rng, NDIRRangeCalib.INDEX_BETA_A) beta_o = self._calib_r_float(rng, NDIRRangeCalib.INDEX_BETA_O) t_cal = self._calib_r_float(rng, NDIRRangeCalib.INDEX_T_CAL) return NDIRRangeCalib(zero, span, linear_b, linear_c, alpha_low, alpha_high, beta_a, beta_o, t_cal) def reload_calib(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('cl') self._transact(cmd) time.sleep(cmd.execution_time) finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # lamp... def lamp_run(self, on): try: self.obtain_lock() on_byte = 1 if on else 0 cmd = SPINDIRx1Cmd.find('lr') self._transact(cmd, (on_byte, )) finally: self.release_lock() def lamp_level(self, voltage): try: self.obtain_lock() voltage_bytes = Encode.float(voltage, '<') cmd = SPINDIRx1Cmd.find('ll') self._transact(cmd, voltage_bytes) finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # low-level commands... def get_sample_mode(self, single_shot): try: self.obtain_lock() mode_byte = 1 if single_shot else 0 cmd = SPINDIRx1Cmd.find('sm') self._transact(cmd, (mode_byte, )) time.sleep(cmd.execution_time) finally: self.release_lock() def get_sample_raw(self): try: self.obtain_lock() # report... cmd = SPINDIRx1Cmd.find('sr') response = self._transact(cmd) pile_ref_amplitude = Decode.unsigned_int(response[0:2], '<') pile_act_amplitude = Decode.unsigned_int(response[2:4], '<') thermistor_average = Decode.unsigned_int(response[4:6], '<') return pile_ref_amplitude, pile_act_amplitude, thermistor_average finally: self.release_lock() def get_sample_voltage(self): try: self.obtain_lock() # report... cmd = SPINDIRx1Cmd.find('sv') response = self._transact(cmd) pile_ref_amplitude = Decode.float(response[0:4], '<') pile_act_amplitude = Decode.float(response[4:8], '<') thermistor_average = Decode.float(response[8:12], '<') # print("pile_ref_amplitude: %s pile_act_amplitude: %s thermistor_average: %s" % \ # (pile_ref_amplitude, pile_act_amplitude, thermistor_average)) return pile_ref_amplitude, pile_act_amplitude, thermistor_average finally: self.release_lock() def get_sample_offsets(self): try: self.obtain_lock() # report... cmd = SPINDIRx1Cmd.find('so') response = self._transact(cmd) min_ref_offset = Decode.unsigned_int(response[0:2], '<') min_act_offset = Decode.unsigned_int(response[2:4], '<') max_ref_offset = Decode.unsigned_int(response[4:6], '<') max_act_offset = Decode.unsigned_int(response[6:8], '<') return min_ref_offset, min_act_offset, max_ref_offset, max_act_offset finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def measure_calibrate(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('mc') self._transact(cmd) time.sleep(cmd.execution_time) finally: self.release_lock() def measure_raw(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('mr') response = self._transact(cmd) pile_ref_value = Decode.unsigned_int(response[0:2], '<') pile_act_value = Decode.unsigned_int(response[2:4], '<') thermistor_value = Decode.unsigned_int(response[4:6], '<') return pile_ref_value, pile_act_value, thermistor_value finally: self.release_lock() def measure_voltage(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('mv') response = self._transact(cmd) pile_ref_voltage = Decode.float(response[0:4], '<') pile_act_voltage = Decode.float(response[4:8], '<') thermistor_voltage = Decode.float(response[8:12], '<') return pile_ref_voltage, pile_act_voltage, thermistor_voltage finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def record_raw(self, deferral, interval, count): try: self.obtain_lock() # start recording... deferral_bytes = Encode.unsigned_int(deferral, '<') interval_bytes = Encode.unsigned_int(interval, '<') count_bytes = Encode.unsigned_int(count, '<') param_bytes = [] param_bytes.extend(deferral_bytes) param_bytes.extend(interval_bytes) param_bytes.extend(count_bytes) cmd = SPINDIRx1Cmd.find('rs') self._transact(cmd, param_bytes) # wait... execution_time = cmd.execution_time + (( (interval * count) + deferral) / 1000) # print("execution time: %s" % execution_time, file=sys.stderr) time.sleep(execution_time) # playback... cmd = SPINDIRx1Cmd.find('rp') cmd.return_count = count * 10 response = self._transact(cmd) values = [] for i in range(0, cmd.return_count, 10): timestamp = Decode.unsigned_int(response[i:i + 2], '<') pile_ref = Decode.long(response[i + 2:i + 6], '<') pile_act = Decode.long(response[i + 6:i + 10], '<') values.append((timestamp, pile_ref, pile_act)) return values finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def input_raw(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('ir') response = self._transact(cmd) v_in_value = Decode.unsigned_int(response, '<') return v_in_value finally: self.release_lock() def input_voltage(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('iv') response = self._transact(cmd) v_in_voltage = Decode.float(response, '<') return v_in_voltage finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def watchdog_clear(self): try: self.obtain_lock() cmd = SPINDIRx1Cmd.find('wc') self._transact(cmd) finally: self.release_lock() def reset(self): try: self.obtain_lock() # force reset... cmd = SPINDIRx1Cmd.find('wr') self._transact(cmd) time.sleep(cmd.execution_time) # clear status... cmd = SPINDIRx1Cmd.find('wc') self._transact(cmd) finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # arbitrary command, used for tests purposes... def cmd(self, name, response_time, execution_time, return_count): command = SPINDIRx1Cmd(name, response_time, execution_time, return_count) try: self.obtain_lock() self._transact(command) time.sleep(execution_time) finally: self.release_lock() # ---------------------------------------------------------------------------------------------------------------- # low-level calib functions... def _calib_r_unsigned_int(self, block, index): cmd = SPINDIRx1Cmd.find('cr') cmd.return_count = 2 response = self._transact(cmd, (block, index)) value = Decode.unsigned_int(response, '<') return value def _calib_w_unsigned_int(self, block, index, value): cmd = SPINDIRx1Cmd.find('cw') value_bytes = Encode.unsigned_int(value, '<') self._transact(cmd, (block, index), value_bytes) time.sleep(cmd.execution_time) def _calib_r_unsigned_long(self, block, index): cmd = SPINDIRx1Cmd.find('cr') cmd.return_count = 4 response = self._transact(cmd, (block, index)) value = Decode.unsigned_long(response, '<') return value def _calib_w_unsigned_long(self, block, index, value): cmd = SPINDIRx1Cmd.find('cw') value_bytes = Encode.unsigned_long(value, '<') self._transact(cmd, (block, index), value_bytes) time.sleep(cmd.execution_time) def _calib_r_float(self, block, index): cmd = SPINDIRx1Cmd.find('cr') cmd.return_count = 4 response = self._transact(cmd, (block, index)) value = Decode.float(response, '<') return value def _calib_w_float(self, block, index, value): cmd = SPINDIRx1Cmd.find('cw') value_bytes = Encode.float(value, '<') self._transact(cmd, (block, index), value_bytes) time.sleep(cmd.execution_time) # ---------------------------------------------------------------------------------------------------------------- # SPI interactions... def _transact(self, cmd, param_group_1=None, param_group_2=None): # print("cmd: %s param_group_1:%s param_group_2:%s" % # (cmd, str(param_group_1), str(param_group_2)), file=sys.stderr) try: self.__spi.open() # start_time = time.time() # command... self.__xfer(cmd.name_bytes()) if param_group_1: time.sleep(self.__PARAM_DELAY) self.__xfer(param_group_1) if param_group_2: time.sleep(self.__PARAM_DELAY) self.__xfer(param_group_2) # elapsed_time = time.time() - start_time # print("elapsed 1: %0.6f" % elapsed_time, file=sys.stderr) # wait... time.sleep(cmd.response_time) # start_time = time.time() # ACK / NACK... response = self.__spi.read_bytes(1) # print("response 1: %s" % str(response), file=sys.stderr) if response[0] in self.__RESPONSE_NONE: raise NDIRException('None received', response[0], cmd, (param_group_1, param_group_2)) if response[0] == self.__RESPONSE_NACK: raise NDIRException('NACK received', response[0], cmd, (param_group_1, param_group_2)) if response[0] == self.__RESPONSE_BUSY: raise NDIRException('BUSY received', response[0], cmd, (param_group_1, param_group_2)) # elapsed_time = time.time() - start_time # print("elapsed 2: %0.6f" % elapsed_time, file=sys.stderr) # return values... if cmd.return_count < 1: return # wait... time.sleep(self.__PARAM_DELAY) # start_time = time.time() response = self.__spi.read_bytes(cmd.return_count) # print("response 2: %s" % str(response), file=sys.stderr) # elapsed_time = time.time() - start_time # print("elapsed 3: %0.6f" % elapsed_time, file=sys.stderr) return response[0] if cmd.return_count == 1 else response finally: self.__spi.close() def wait(self): try: self.__spi.open() start_time = time.time() response = self.__spi.read_bytes(1) elapsed_time = time.time() - start_time print("wait: %s: 0x%02x" % (elapsed_time, response[0])) finally: self.__spi.close() def __xfer(self, values): self.__spi.xfer(list(values)) # ---------------------------------------------------------------------------------------------------------------- def __str__(self, *args, **kwargs): return "SPINDIRx1:{interface:%s, spi:%s}" % (self.interface, self.__spi)
class Display(object): """ classdocs """ COLOUR = "black" CLEAR_TIME = 1.0 # seconds DRAW_TIME = 6.0 # seconds DEFAULT_CLEAN_CYCLES = 1 __LOCK_TIMEOUT = 20.0 # seconds __SPI_BUS = 0 __SPI_DEVICE = 0 __SPI_CLOCK = 300000 # Hz was 488000 __SPI_MODE = 1 # ---------------------------------------------------------------------------------------------------------------- def __init__(self, font): """ Constructor """ self.__font = font self.__device = InkyPHAT(self.COLOUR) self.__image = Image.new("P", (self.__device.WIDTH, self.__device.HEIGHT)) self.__drawing = ImageDraw.Draw(self.__image) m_width, m_height = self.__font.getsize("M") self.__text_width = self.__device.WIDTH // m_width self.__text_height = self.__device.HEIGHT // m_height + 1 self.__stop = None self.__render_timeout = Timeout(self.DRAW_TIME) # self.__spi = SPI(self.__SPI_BUS, self.__SPI_DEVICE, None, None) self.__spi = SPI(self.__SPI_BUS, self.__SPI_DEVICE, self.__SPI_MODE, self.__SPI_CLOCK) # ---------------------------------------------------------------------------------------------------------------- def clean(self, cycles=None): try: self.obtain_lock() for _ in range( self.DEFAULT_CLEAN_CYCLES if cycles is None else cycles): # clear... self.__image = Image.new( "P", (self.__device.WIDTH, self.__device.HEIGHT)) self.__drawing = ImageDraw.Draw(self.__image) self.__show() finally: self.release_lock() def clear(self): try: self.obtain_lock() self.__image = Image.new( "P", (self.__device.WIDTH, self.__device.HEIGHT)) self.__drawing = ImageDraw.Draw(self.__image) time.sleep(self.CLEAR_TIME) finally: self.release_lock() def draw_text(self, buffer): try: self.obtain_lock() for row in range(len(buffer)): y_offset = row * self.__text_height self.__drawing.text((0, y_offset), buffer[row], self.__device.BLACK, self.__font) finally: self.release_lock() def render(self): try: self.obtain_lock() print("Display: starting render", file=sys.stderr) sys.stderr.flush() self.__show() except TimeoutError: print("Display: render timeout", file=sys.stderr) sys.stderr.flush() finally: self.release_lock() print("Display: ending render", file=sys.stderr) sys.stderr.flush() # ---------------------------------------------------------------------------------------------------------------- def __show(self): # update... self.__device.set_image(self.__image) # show... with self.__render_timeout: try: self.__spi.acquire_lock() self.__device.show( ) # Do not let the display enter deep sleep - OPC affected!? finally: self.__spi.release_lock() # wait... time.sleep(self.DRAW_TIME) # ---------------------------------------------------------------------------------------------------------------- def obtain_lock(self): Lock.acquire(self.__lock_name, self.__LOCK_TIMEOUT) def release_lock(self): Lock.release(self.__lock_name) @property def __lock_name(self): return self.__class__.__name__ # ---------------------------------------------------------------------------------------------------------------- @property def text_width(self): return self.__text_width @property def text_height(self): return self.__text_height # ---------------------------------------------------------------------------------------------------------------- def __str__(self, *args, **kwargs): return "Display:{text_width:%s, text_height:%s, colour:%s, render_timeout:%s, spi:%s}" % \ (self.text_width, self.text_height, self.COLOUR, self.__render_timeout, self.__spi)
def __init__(self, spi_bus, spi_device, spi_mode, spi_clock): """ Constructor """ self._io = None self._spi = SPI(spi_bus, spi_device, spi_mode, spi_clock)
class OPCN2(object): """ classdocs """ SOURCE = 'N2' MIN_SAMPLE_PERIOD = 5.0 # seconds MAX_SAMPLE_PERIOD = 10.0 # seconds DEFAULT_SAMPLE_PERIOD = 10.0 # seconds POWER_CYCLE_TIME = 10.0 # seconds # ---------------------------------------------------------------------------------------------------------------- __BOOT_TIME = 4.0 # seconds __START_TIME = 5.0 # seconds __STOP_TIME = 2.0 # seconds __FLOW_RATE_VERSION = 16 __FAN_UP_TIME = 10 __FAN_DOWN_TIME = 2 __PERIOD_CONVERSION = 45360 # should be 12000 (1/12MHz * 1000), but found by experiment __CMD_POWER = 0x03 __CMD_POWER_ON = 0x00 # 0x03, 0x00 __CMD_POWER_OFF = 0x01 # 0x03, 0x01 __CMD_CHECK_STATUS = 0xcf __CMD_READ_HISTOGRAM = 0x30 __CMD_GET_FIRMWARE_VERSION = 0x3f __SPI_CLOCK = 488000 __SPI_MODE = 1 __CMD_DELAY = 0.01 __TRANSFER_DELAY = 0.00002 __LOCK_TIMEOUT = 6.0 # ---------------------------------------------------------------------------------------------------------------- @classmethod def obtain_lock(cls): Lock.acquire(cls.__name__, OPCN2.__LOCK_TIMEOUT) @classmethod def release_lock(cls): Lock.release(cls.__name__) # ---------------------------------------------------------------------------------------------------------------- def __init__(self, spi_bus, spi_device): """ Constructor """ self.__io = IO() self.__spi = SPI(spi_bus, spi_device, OPCN2.__SPI_MODE, OPCN2.__SPI_CLOCK) # ---------------------------------------------------------------------------------------------------------------- def power_on(self): initial_power_state = self.__io.opc_power self.__io.opc_power = IO.LOW if initial_power_state == IO.HIGH: # initial_power is None if there is no power control facility time.sleep(self.__BOOT_TIME) def power_off(self): self.__io.opc_power = IO.HIGH # ---------------------------------------------------------------------------------------------------------------- def operations_on(self): try: self.obtain_lock() self.__spi.open() # start... self.__spi.xfer([OPCN2.__CMD_POWER, OPCN2.__CMD_POWER_ON]) time.sleep(OPCN2.__START_TIME) # clear histogram... self.__spi.xfer([OPCN2.__CMD_READ_HISTOGRAM]) time.sleep(OPCN2.__CMD_DELAY) for _ in range(62): self.__read_byte() finally: self.__spi.close() self.release_lock() def operations_off(self): try: self.obtain_lock() self.__spi.open() self.__spi.xfer([OPCN2.__CMD_POWER, OPCN2.__CMD_POWER_OFF]) finally: time.sleep(OPCN2.__CMD_DELAY) self.__spi.close() self.release_lock() time.sleep(OPCN2.__STOP_TIME) # ---------------------------------------------------------------------------------------------------------------- def sample(self): try: self.obtain_lock() self.__spi.open() self.__spi.xfer([OPCN2.__CMD_READ_HISTOGRAM]) time.sleep(OPCN2.__CMD_DELAY) # bins... bins = [None] * 16 for i in range(16): bins[i] = self.__read_int() # bin MToFs... bin_1_mtof = self.__read_byte() bin_3_mtof = self.__read_byte() bin_5_mtof = self.__read_byte() bin_7_mtof = self.__read_byte() # flow rate... self.__spi.read_bytes(4) # temperature self.__spi.read_bytes(4) # period... period = self.__read_float() # checksum... self.__read_int() # PMx... try: pm = self.__read_float() pm1 = 0.0 if pm < 0 else pm except TypeError: pm1 = None try: pm = self.__read_float() pm2p5 = 0.0 if pm < 0 else pm except TypeError: pm2p5 = None try: pm = self.__read_float() pm10 = 0.0 if pm < 0 else pm except TypeError: pm10 = None now = LocalizedDatetime.now() return OPCDatum(self.SOURCE, now, pm1, pm2p5, pm10, period, bins, bin_1_mtof, bin_3_mtof, bin_5_mtof, bin_7_mtof) finally: time.sleep(OPCN2.__CMD_DELAY) self.__spi.close() self.release_lock() def firmware(self): try: self.obtain_lock() self.__spi.open() self.__spi.xfer([OPCN2.__CMD_GET_FIRMWARE_VERSION]) time.sleep(OPCN2.__CMD_DELAY) read_bytes = [] for _ in range(60): time.sleep(OPCN2.__TRANSFER_DELAY) read_bytes.extend(self.__spi.read_bytes(1)) report = ''.join(chr(b) for b in read_bytes) return report.strip( '\0\xff') # \0 - Raspberry Pi, \xff - BeagleBone finally: time.sleep(OPCN2.__CMD_DELAY) self.__spi.close() self.release_lock() # ---------------------------------------------------------------------------------------------------------------- def __read_byte(self): time.sleep(OPCN2.__TRANSFER_DELAY) read_bytes = self.__spi.read_bytes(1) return read_bytes[0] def __read_int(self): read_bytes = [] for _ in range(2): time.sleep(OPCN2.__TRANSFER_DELAY) read_bytes.extend(self.__spi.read_bytes(1)) return Decode.unsigned_int(read_bytes) def __read_float(self): read_bytes = [] for _ in range(4): time.sleep(OPCN2.__TRANSFER_DELAY) read_bytes.extend(self.__spi.read_bytes(1)) return Decode.float(read_bytes) # ---------------------------------------------------------------------------------------------------------------- def __str__(self, *args, **kwargs): return "OPCN2:{io:%s, spi:%s}" % (self.__io, self.__spi)