def __get_device_data(self, address): product_type = None node_identifier = None try: device_data = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'DD', use_cache=True) except: # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning(("XBeeAutoEnum: __add_new_device. " + "UNABLE to get DD from %s."), address) return product_type, node_identifier device_type, product_type = parse_dd(device_data) # Now ask the device what its Node Identification is. try: node_identifier = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'NI', use_cache=True) except: # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning("XBeeAutoEnum: __add_new_device. " + "UNABLE to get NI from %s.", address) return product_type, node_identifier return product_type, node_identifier
def __get_device_data(self, address): product_type = None node_identifier = None try: device_data = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'DD', use_cache=True) except: # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning(('XBeeAutoEnum: __add_new_device. ' 'UNABLE to get DD from %s.'), address) return product_type, node_identifier _, product_type = parse_dd(device_data) # Now ask the device what its Node Identification is. try: node_identifier = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'NI', use_cache=True) except: # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning( 'XBeeAutoEnum: __add_new_device. ' 'UNABLE to get NI from %s.', address) return product_type, node_identifier return product_type, node_identifier
def __is_sleep_mode_available(self, ext_addr=False): ''' If ext_addr is False, uses the device referred to in this config block. ''' # Special case: if this is a ZB network we need to check if the # firmware version is less than 0x2x60. If it is less than this, # then sleep mode is not supported on router modules (0x2260): if ext_addr == False: ext_addr = AbstractXBeeConfigBlockDDO.ext_addr_get(self) module_id, _ = parse_dd(AbstractXBeeConfigBlockDDO.\ configurator_get(self)\ .ddo_get_param(ext_addr, 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True)) if module_id not in SLEEPABLE_MODULES: return False if module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: fw_func, fw_v = parse_vr(AbstractXBeeConfigBlockDDO.\ configurator_get(self).\ ddo_get_param(ext_addr, 'VR', retries=\ DDO_RETRY_ATTEMPTS, use_cache=True)) if (fw_func in UNSUPPORTED_ZB_FW_FUNCSETS and fw_v < UNSUPPORTED_ZB_LT_FW_VERSION): self.__tracer.warning( "'%s' FW version is %s < %s, " "sleep mode configuration unavailable.", ext_addr, hex(fw_v), hex(UNSUPPORTED_ZB_LT_FW_VERSION)) return False return True
def running_indication(self): # request initial status here. self.__tracer.info("Running indication") extended_address = SettingsBase.get_setting(self, "extended_address") humidity_present = SettingsBase.get_setting(self, "humidity_present") # this is a flawed design - if the gateway has just rebooted, # and the Xbee sensor sleeps (which it should), then an actual # GET_DDO will be issued, which causes Dia to freeze here and # almost certainly throw exception and put the device off line. try: dd_value = self.__xbee_manager.xbee_device_ddo_get_param( extended_address, 'DD', use_cache=True) except: self.__tracer.warning('Using default DD') dd_value = 0x0003000E module_id, product_id = parse_dd(dd_value) self.__tracer.info('DD info (module_id, product_id) = ' + '(0x%04x, 0x%04x)"', module_id, product_id) if product_id == PROD_DIGI_XB_SENSOR_LTH or humidity_present == True: self.__tracer.info("Sensor is a '%s' adding humidity channel", product_name(product_id)) self.add_property( ChannelSourceDeviceProperty(name="humidity", type=float, initial=Sample(timestamp=0, value=0.0, unit="%"), perms_mask=DPROP_PERM_GET, options=DPROP_OPT_AUTOTIMESTAMP)) else: self.__tracer.info("Sensor is a '%s' no humidity capability.", product_name(product_id))
def __get_device_data(self, address): product_type = None node_identifier = None device_data = None try: device_data = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'DD', use_cache=True) except: device_data = None # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning(('XBeeAutoEnum: __add_new_device. ' 'UNABLE to get DD from %s.'), address) return product_type, node_identifier, device_data _, product_type = parse_dd(device_data) print "here is the stuff you are looking for" print _ print product_type # Now ask the device what its Node Identification is. try: node_identifier = self.__xbee_manager.xbee_device_ddo_get_param(\ address, 'NI', use_cache=True) except: # On any exceptions, just bail. # The next discovery we will take another crack at it. self.__tracer.warning('XBeeAutoEnum: __add_new_device. ' 'UNABLE to get NI from %s.', address) return product_type, node_identifier, device_data return product_type, node_identifier, device_data
def __is_sleep_mode_available(self): # Special case: if this is a ZB network we need to check if the # firmware version is less than 0x2x60. If it is less than this, # then sleep mode is not supported on router modules (0x2260): xbee_dd_ddo_value = \ AbstractXBeeConfigBlockDDO.configurator_get(self).ddo_get_param( AbstractXBeeConfigBlockDDO.ext_addr_get(self), 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) if module_id not in (MOD_XB_ZNET25, MOD_XB_ZB, MOD_XB_S2C_ZB): # Sleep unsupported return False if module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: xbee_vr_ddo_value = \ AbstractXBeeConfigBlockDDO.configurator_get(self).ddo_get_param( AbstractXBeeConfigBlockDDO.ext_addr_get(self), 'VR', retries=DDO_RETRY_ATTEMPTS, use_cache=True) fw_funcset, fw_version = parse_vr(xbee_vr_ddo_value) if (fw_funcset in UNSUPPORTED_ZB_FW_FUNCSETS and fw_version < UNSUPPORTED_ZB_LT_FW_VERSION): self.__tracer.warning("'%s' FW version is %s < %s, " + "sleep mode configuration unavailable.", AbstractXBeeConfigBlockDDO.ext_addr_get(self), hex(fw_version), hex(UNSUPPORTED_ZB_LT_FW_VERSION)) return False return True
def _is_applicable(self, xbee_dd_ddo_value=None): """ Test if this XBee configuration block is applicable given combinations of apply_except_* and apply_only_* filters. This method is intended to be used by derived classes in order to test applicability before allowing :meth:`apply_config` to perform any actions. See :meth:`apply_config` for a code example. This method may be hinted with `xbee_dd_ddo_value` in order to avoid this method from attempting to access the network (or hit the DDO parameter cache) to determine which module_id and product_id are valid for the extended address of the node this XBee configuration block will act upon. Parameters: * **xbee_dd_ddo_value**: an XBee DD DDO value that will be decoded to a module_id and product_id. Return type: * bool """ if not xbee_dd_ddo_value: xbee_dd_ddo_value = self.__configurator.ddo_get_param( self.__ext_addr, 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) applicability = True if self.__module_applicability == self.APPLICABILITY_ONLY: applicability &= module_id in self.__modules elif self.__module_applicability == self.APPLICABILITY_EXCEPT: applicability &= module_id not in self.__modules if self.__product_applicability == self.APPLICABILITY_ONLY: applicability &= product_id in self.__products elif self.__product_applicability == self.APPLICABILITY_EXCEPT: applicability &= product_id not in self.__products return applicability
def _is_applicable(self, xbee_dd_ddo_value=None): """ Test if this XBee configuration block is applicable given combinations of apply_except_* and apply_only_* filters. This method is intended to be used by derived classes in order to test applicability before allowing :meth:`apply_config` to perform any actions. See :meth:`apply_config` for a code example. This method may be hinted with `xbee_dd_ddo_value` in order to avoid this method from attempting to access the network (or hit the DDO parameter cache) to determine which module_id and product_id are valid for the extended address of the node this XBee configuration block will act upon. Parameters: * **xbee_dd_ddo_value**: an XBee DD DDO value that will be decoded to a module_id and product_id. Return type: * bool """ if not xbee_dd_ddo_value: xbee_dd_ddo_value = self.__configurator.ddo_get_param( self._ext_addr, 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) applicability = True if self.__module_applicability == self.APPLICABILITY_ONLY: applicability &= module_id in self.__modules elif self.__module_applicability == self.APPLICABILITY_EXCEPT: applicability &= module_id not in self.__modules if self.__product_applicability == self.APPLICABILITY_ONLY: applicability &= product_id in self.__products elif self.__product_applicability == self.APPLICABILITY_EXCEPT: applicability &= product_id not in self.__products return applicability
def running_indication(self): # request initial status here. self._tracer.info("Running indication") humidity_present = SettingsBase.get_setting(self, "humidity_present") # this is a flawed design - if the gateway has just rebooted, # and the Xbee sensor sleeps (which it should), then an actual # GET_DDO will be issued, which causes DIA to freeze here and # almost certainly throw exception and put the device off line. try: dd_value = self._xbee_manager.xbee_device_ddo_get_param( self._extended_address, 'DD', use_cache=True) except: self._tracer.warning('Using default DD') dd_value = 0x0003000E module_id, product_id = parse_dd(dd_value) self._tracer.debug( 'DD info (module_id, product_id) = ' + '(0x%04x, 0x%04x)"', module_id, product_id) if product_id == PROD_DIGI_XB_SENSOR_LTH or humidity_present == True: self._tracer.info("Sensor is a '%s' adding humidity channel", product_name(product_id)) self.add_property( ChannelSourceDeviceProperty(name="humidity", type=float, initial=Sample(timestamp=0, value=0.0, unit="%"), perms_mask=DPROP_PERM_GET, options=DPROP_OPT_AUTOTIMESTAMP)) else: self._tracer.info("Sensor is a '%s' no humidity capability.", product_name(product_id))
def calibrate(self): """\ Calibrate analog inputs on the XBee radio. Calculates scale and offset. """ # Retrieve the radio type. # Calibration is different based on the XBee radio in the unit. xbee_dd_ddo_value = self.__xbee_manager.xbee_device_ddo_get_param(None, 'DD', use_cache = True) module_id, product_id = parse_dd(xbee_dd_ddo_value) # XBee series 1 uses one calibration voltage on AN2 if module_id == MOD_XB_802154: # Enable calibration voltages on channel 1 for ch in self.__aio_channel_structures: if ch.channel() == 1: ch.turn_on_calibration_series1() # Give it a moment to synch up. Yes, this IS required! digitime.sleep(0.010) # Read calibration sample result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') sample = parse_is(result)["AD1"] self.__tracer.debug("Calibration sample is %d", sample) # Disable calibration voltages on channels 0 and 1 for ch in self.__aio_channel_structures: if ch.channel() == 0 or ch.channel() == 1: ch.turn_off_calibration_series2() # Give it a moment to synch up. Yes, this IS required! digitime.sleep(0.010) if sample == 0: raise ValueError, "Calibration error: bad sample" # Calulate linear scale and offset. # These apply to all analog channels. self.__scale = 1.25 / sample self.__offset = 0 # XBee series 2 uses two calibration voltages on AN1 and AN2 elif module_id == MOD_XB_ZNET25 or module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: # Enable calibration voltages on channels 0 and 1 for ch in self.__aio_channel_structures: if ch.channel() == 0 or ch.channel() == 1: ch.turn_on_calibration_series2() # Give it a moment to synch up. Yes, this IS required! digitime.sleep(0.010) # Read calibration samples result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') data = parse_is(result) sample = [ data["AD0"], data["AD1"] ] self.__tracer.debug("Calibration samples are %d, %d", sample[0], sample[1]) # Disable calibration voltages on channels 0 and 1 for ch in self.__aio_channel_structures: if ch.channel() == 0 or ch.channel() == 1: ch.turn_off_calibration_series2() # Give it a moment to synch up. Yes, this IS required! digitime.sleep(0.010) if sample[0] == sample[1]: raise ValueError, "Calibration error: equal samples" scale1 = self.__CALIBRATION_06 / float(sample[1]) scale2 = self.__CALIBRATION_10 / float(sample[0]) self.__scale = (scale1 + scale2) / 2.0 if self.__OLD_HARDWARE == True: self.__offset = (sample[1] * self.__scale - self.LOCAL_AIO_CALIBRATION_06) * 2.4 else: self.__offset = 0.0 else: raise ValueError, "XBee does not support analog inputs" self.__calibration_time = digitime.real_clock() self.__tracer.debug("Scale is %f, offset is %f", self.__scale, self.__offset)
def start(self): # Fetch the XBee Manager name from the Settings Manager: xbee_manager_name = SettingsBase.get_setting(self, "xbee_device_manager") dm = self.__core.get_service("device_driver_manager") self.__xbee_manager = dm.instance_get(xbee_manager_name) # Register ourselves with the XBee Device Manager instance: self.__xbee_manager.xbee_device_register(self) # Get the extended address of the device: extended_address = SettingsBase.get_setting(self, "extended_address") # Retrieve the flag which tells us if we should sleep: # Create a callback specification for our device address, endpoint # Digi XBee profile and sample cluster id: xbdm_rx_event_spec = XBeeDeviceManagerRxEventSpec() xbdm_rx_event_spec.cb_set(self.sample_indication) xbdm_rx_event_spec.match_spec_set( (extended_address, 0xe8, 0xc105, 0x92), (True, True, True, True)) self.__xbee_manager.xbee_device_event_spec_add(self, xbdm_rx_event_spec) # Create a callback specification that calls back this driver when # our device has left the configuring state and has transitioned # to the running state: xbdm_running_event_spec = XBeeDeviceManagerRunningEventSpec() xbdm_running_event_spec.cb_set(self.running_indication) self.__xbee_manager.xbee_device_event_spec_add(self, xbdm_running_event_spec) # Create a DDO configuration block for this device: xbee_ddo_cfg = XBeeConfigBlockDDO(extended_address) # Get the gateway's extended address: gw_xbee_sh, gw_xbee_sl = gw_extended_address_tuple() # Set the destination for I/O samples to be the gateway: xbee_ddo_cfg.add_parameter('DH', gw_xbee_sh) xbee_ddo_cfg.add_parameter('DL', gw_xbee_sl) # Configure pins DI1 .. DI3 for analog input: for io_pin in [ 'D1', 'D2', 'D3' ]: xbee_ddo_cfg.add_parameter(io_pin, 2) # Configure battery-monitor pin DIO11/P1 for digital input: xbee_ddo_cfg.add_parameter('P1', 3) # Enable change detection on DIO11: # # 0x 8 0 0 # 1000 0000 0000 (b) # DDDD DDDD DDDD # IIII IIII IIII # OOOO OOOO OOOO # 1198 7654 3210 # 10 # xbee_ddo_cfg.add_parameter('IC', 0x800) if SettingsBase.get_setting(self, "humidity_present"): # Get gateway module_id, universal to all nodes on the network: gw_dd = self.__xbee_manager.xbee_device_ddo_get_param( None, 'DD', use_cache=True) module_id, product_id = parse_dd(gw_dd) # Re-program DD value to set sensor type to /L/T/H: device_dd = format_dd(module_id, PROD_DIGI_XB_SENSOR_LTH) xbee_ddo_cfg.add_parameter('DD', device_dd) # Configure the IO Sample Rate: # Clip sample_rate_ms to the max value of IR: sample_rate_ms = SettingsBase.get_setting(self, "sample_rate_ms") sample_rate_ms = min(sample_rate_ms, 0xffff) xbee_ddo_cfg.add_parameter('IR', sample_rate_ms) # Register this configuration block with the XBee Device Manager: self.__xbee_manager.xbee_device_config_block_add(self, xbee_ddo_cfg) # Setup the sleep parameters on this device: will_sleep = SettingsBase.get_setting(self, "sleep") sample_predelay = SettingsBase.get_setting(self, "sample_predelay") awake_time_ms = (SettingsBase.get_setting(self, "awake_time_ms") + sample_predelay) if will_sleep: # Sample time pre-delay, allow the circuitry to power up and # settle before we allow the XBee to send us a sample: xbee_ddo_wh_block = XBeeConfigBlockDDO(extended_address) xbee_ddo_wh_block.apply_only_to_modules((MOD_XB_ZB, MOD_XB_S2C_ZB,)) xbee_ddo_wh_block.add_parameter('WH', sample_predelay) self.__xbee_manager.xbee_device_config_block_add(self, xbee_ddo_wh_block) # The original sample rate is used as the sleep rate: sleep_rate_ms = SettingsBase.get_setting(self, "sample_rate_ms") xbee_sleep_cfg = XBeeConfigBlockSleep(extended_address) if will_sleep: xbee_sleep_cfg.sleep_cycle_set(awake_time_ms, sleep_rate_ms) else: xbee_sleep_cfg.sleep_mode_set(SM_DISABLED) self.__xbee_manager.xbee_device_config_block_add(self, xbee_sleep_cfg) # Indicate that we have no more configuration to add: self.__xbee_manager.xbee_device_configure(self) return True
def __calibrate(self): """__calibrate() Calibrate analog inputs. Calculates scale and offset.""" xbee_dd_ddo_value = self.__xbee_manager.xbee_device_ddo_get_param(None, 'DD', use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) # XBee series 1 uses one calibration voltage on AN2 if module_id == MOD_XB_802154: # Enable calibration voltage on channel 1 self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 4, apply=True) digitime.sleep(0.010) # Read calibration sample result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') sample = parse_is(result)["AD1"] self.__tracer.debug("Calibration sample is %d", sample) # Return channel to operating mode self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 5, apply=True) digitime.sleep(0.010) if sample == 0: raise ValueError, "Calibration error: bad sample" # Calulate linear scale and offset. # These apply to all analog channels. self.__scale = 1.25 / sample self.__offset = 0 # XBee series 2 uses two calibration voltages on AN1 and AN2 elif module_id == MOD_XB_ZNET25 or module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: # Enable calibration voltages on channels 0 and 1 if get_platform_name() == 'digix3': self.__xbee_manager.xbee_device_ddo_set_param(None, self.LOCAL_AIO_CONTROL_LINES[0], 2, apply=True) self.__xbee_manager.xbee_device_ddo_set_param(None, self.LOCAL_AIO_CONTROL_LINES[1], 2, apply=True) digihw.gpio_set_value(0, 0) elif get_platform_name() == 'digiconnect': self.__xbee_manager.xbee_device_ddo_set_param(None, 'P2', 4, apply=True) self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 4, apply=True) digitime.sleep(0.010) # Read calibration samples result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') data = parse_is(result) sample = [ data["AD0"], data["AD1"] ] self.__tracer.debug("Calibration samples are %d, %d", sample[0], sample[1]) # Return channels to operating mode if get_platform_name() == 'digix3': digihw.gpio_set_value(0, 1) elif get_platform_name() == 'digiconnect': self.__xbee_manager.xbee_device_ddo_set_param(None, 'P2', 5, apply=True) self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 5, apply=True) digitime.sleep(0.010) for io_pin in range(2): mode = SettingsBase.get_setting(self, 'channel%d_mode' % (io_pin+1) ) mode = self.LOCAL_AIO_MODE_MAP[mode.lower()] if mode == self.LOCAL_AIO_MODE_CURRENTLOOP: self.__xbee_manager.xbee_device_ddo_set_param(None, self.LOCAL_AIO_CONTROL_LINES[io_pin], 2, apply=True) elif mode == self.LOCAL_AIO_MODE_TENV: self.__xbee_manager.xbee_device_ddo_set_param(None, self.LOCAL_AIO_CONTROL_LINES[io_pin], 2, apply=True) if sample[0] == sample[1]: raise ValueError, "Calibration error: equal samples" self.__sample1 = sample[1] self.__sample2 = sample[0] scale1 = self.LOCAL_AIO_CALIBRATION_06 / float(sample[1]) scale2 = self.LOCAL_AIO_CALIBRATION_10 / float(sample[0]) self.__scale = (scale1 + scale2) / 2.0 if self.__OLD_HARDWARE == True: self.__offset = (self.__sample1 * self.__scale - self.LOCAL_AIO_CALIBRATION_06) * 2.4 else: self.__offset = 0.0 else: raise ValueError, "XBee does not support analog inputs" self.__calibration_time = digitime.real_clock() self.__tracer.debug("Scale is %f, offset is %f", self.__scale, self.__offset)
def prepare_network(self, override_map=None): ''' Setup the network to handle this node. It is important that all routers and the coordinator be prepared to reach a node with sleeping parameters. Without preparing the network first, reaching the node to configure it (if it has been preconfigured, for instance) may leave the node unreachable! This method will be called as a special case from the XBeeDeviceManager at the appropriate time. Return type: * bool ''' if self.__sleep_mode == SM_DISABLED: return # Test local node for sleep fitness: if not self.__is_sleep_mode_available(None): return False if self.__sleep_mode == DM_SUPPORT: # ensure this device is not a preferred sleep coord # bit 1: non-sleep coordinator # bit 2: enable api sleep status messages self._add_parameter('SO', 0x06) return True if self.__sleep_mode == DM_SLEEP: # ensure not a sleep coordinator self._add_parameter('SO', 0x0) return True # If we are setting up a node for cyclic sleep, we must set # appropriate values for SP and SN (if the values are not already # large enough) network wide so the network may buffer requests # long enough for our sleeping nodes: router_list = (AbstractXBeeConfigBlockDDO.\ xbee_device_manager_get(self)\ .xbee_get_node_list(refresh=False)) router_list = [n.addr_extended for n in router_list if \ n.type == 'router' or n.type == 'coordinator'] write_list = [] module_id, _ = parse_dd(AbstractXBeeConfigBlockDDO.\ configurator_get(self)\ .ddo_get_param(None, 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True)) applicable_params = None if module_id == MOD_XB_ZNET25: # Only SP is valid network wide: applicable_params = ('SP', ) elif module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: applicable_params = ('SP', 'SN') for param in applicable_params: if param in self.__pending_parameters: for network_node in router_list: try: if not self.__prepare_network_update_param( network_node, param, override_map): # no update necessary, continue continue except Exception, e: self.__tracer.warning('Could not prepare network for ' 'sleeping node %s... will ' 'try again later.' % self._ext_addr) return False write_list.append(network_node)
def start(self): self._tracer.calls("XBeeSensor.start()") # init self._xbee_manager and self._extended_address # register ourself with our Xbee manager # create the self.running_indication callback XBeeBase.pre_start(self) # Retrieve the flag which tells us if we should sleep: # Create a callback specification for our device address self._xbee_manager.register_sample_listener(self, self._extended_address, self.sample_indication) # Create a DDO configuration block for this device: xbee_ddo_cfg = XBeeConfigBlockDDO(self._extended_address) # Configure pins DI1 .. DI3 for analog input: for io_pin in ['D1', 'D2', 'D3']: xbee_ddo_cfg.add_parameter(io_pin, 2) # Configure battery-monitor pin DIO11/P1 for digital input: xbee_ddo_cfg.add_parameter('P1', 3) # Enable change detection on DIO11: # # 0x 8 0 0 # 1000 0000 0000 (b) # DDDD DDDD DDDD # IIII IIII IIII # OOOO OOOO OOOO # 1198 7654 3210 # 10 # xbee_ddo_cfg.add_parameter('IC', 0x800) if SettingsBase.get_setting(self, "humidity_present"): # Get gateway module_id, universal to all nodes on the network: gw_dd = self._xbee_manager.xbee_device_ddo_get_param( None, 'DD', use_cache=True) module_id, product_id = parse_dd(gw_dd) # Re-program DD value to set sensor type to /L/T/H: device_dd = format_dd(module_id, PROD_DIGI_XB_SENSOR_LTH) xbee_ddo_cfg.add_parameter('DD', device_dd) # Configure the IO Sample Rate: # Clip sample_rate_ms to the max value of IR: sample_rate_ms = SettingsBase.get_setting(self, "sample_rate_ms") sample_rate_ms = min(sample_rate_ms, 0xffff) xbee_ddo_cfg.add_parameter('IR', sample_rate_ms) # Register this configuration block with the XBee Device Manager: self._xbee_manager.xbee_device_config_block_add(self, xbee_ddo_cfg) # Setup the sleep parameters on this device: will_sleep = SettingsBase.get_setting(self, "sleep") sample_predelay = SettingsBase.get_setting(self, "sample_predelay") awake_time_ms = (SettingsBase.get_setting(self, "awake_time_ms") + sample_predelay) if will_sleep: # Sample time pre-delay, allow the circuitry to power up and # settle before we allow the XBee to send us a sample: xbee_ddo_wh_block = XBeeConfigBlockDDO(self._extended_address) xbee_ddo_wh_block.apply_only_to_modules(( MOD_XB_ZB, MOD_XB_S2C_ZB, )) xbee_ddo_wh_block.add_parameter('WH', sample_predelay) self._xbee_manager.xbee_device_config_block_add( self, xbee_ddo_wh_block) # The original sample rate is used as the sleep rate: sleep_rate_ms = SettingsBase.get_setting(self, "sample_rate_ms") # new method for mesh health monitoring self.set_data_update_rate_seconds(sleep_rate_ms / 1000) # not including sample_predelay here... specially configured above xbee_sleep_cfg = self._xbee_manager.get_sleep_block( self._extended_address, sleep=will_sleep, sleep_rate_ms=sleep_rate_ms, awake_time_ms=awake_time_ms) self._xbee_manager.xbee_device_config_block_add(self, xbee_sleep_cfg) # we've no more to config, indicate we're ready to configure. return XBeeBase.start(self)
def prepare_network(self): """\ Setup the network to handle this node. It is important that all routers and the coordinator be prepared to reach a node with sleeping parameters. Without preparing the network first, reaching the node to configure it (if it has been preconfigured, for instance) may leave the node unreachable! This method will be called as a special case from the XBeeDeviceManager at the appropriate time. Return type: * bool """ if self.__sleep_mode == SM_DISABLED: return # Test local node for sleep fitness: if not self.__is_sleep_mode_available(): return False # If we are setting up a node for cyclic sleep, we must set # appropriate values for SP and SN (if the values are not already # large enough) network wide so the network may buffer requests # long enough for our sleeping nodes: router_list = (AbstractXBeeConfigBlockDDO.xbee_device_manager_get(self) .xbee_get_node_list(refresh=False)) router_list = filter(lambda n: (n.type == 'router' or n.type == 'coordinator'), router_list) router_list = map(lambda n: n.addr_extended, router_list) write_list = [ ] xbee_dd_ddo_value = \ AbstractXBeeConfigBlockDDO.configurator_get(self).ddo_get_param( AbstractXBeeConfigBlockDDO.ext_addr_get(self), 'DD', retries=DDO_RETRY_ATTEMPTS, use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) applicable_params = None if module_id == MOD_XB_ZNET25: # Only SP is valid network wide: applicable_params = ( 'SP', ) elif module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: applicable_params = ( 'SP', 'SN' ) for param in applicable_params: if param in self.__pending_parameters: network_param = None for network_node in router_list: try: if not self.__prepare_network_update_param( network_node, param): # no update necessary, continue continue except Exception, e: # signal to XBeeDeviceManager that network preparation # needs to be retried: # print "XDCBS: Error updating parameter: %s" % repr(e) # print "-" * 60 # traceback.print_exc(file=sys.stdout) # print "-" * 60 return False write_list.append(network_node)
def __calibrate(self): """__calibrate() Calibrate analog inputs. Calculates scale and offset.""" xbee_dd_ddo_value = self.__xbee_manager.xbee_device_ddo_get_param( None, 'DD', use_cache=True) module_id, product_id = parse_dd(xbee_dd_ddo_value) # XBee series 1 uses one calibration voltage on AN2 if module_id == MOD_XB_802154: # Enable calibration voltage on channel 1 self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 4, apply=True) digitime.sleep(0.010) # Read calibration sample result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') sample = parse_is(result)["AD1"] self.__tracer.debug("Calibration sample is %d", sample) # Return channel to operating mode self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 5, apply=True) digitime.sleep(0.010) if sample == 0: raise ValueError, "Calibration error: bad sample" # Calulate linear scale and offset. # These apply to all analog channels. self.__scale = 1.25 / sample self.__offset = 0 # XBee series 2 uses two calibration voltages on AN1 and AN2 elif module_id == MOD_XB_ZNET25 or module_id == MOD_XB_ZB or module_id == MOD_XB_S2C_ZB: # Enable calibration voltages on channels 0 and 1 if get_platform_name() == 'digix3': self.__xbee_manager.xbee_device_ddo_set_param( None, self.LOCAL_AIO_CONTROL_LINES[0], 2, apply=True) self.__xbee_manager.xbee_device_ddo_set_param( None, self.LOCAL_AIO_CONTROL_LINES[1], 2, apply=True) digihw.gpio_set_value(0, 0) elif get_platform_name() == 'digiconnect': self.__xbee_manager.xbee_device_ddo_set_param(None, 'P2', 4, apply=True) self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 4, apply=True) digitime.sleep(0.010) # Read calibration samples result = self.__xbee_manager.xbee_device_ddo_get_param(None, 'IS') data = parse_is(result) sample = [data["AD0"], data["AD1"]] self.__tracer.debug("Calibration samples are %d, %d", sample[0], sample[1]) # Return channels to operating mode if get_platform_name() == 'digix3': digihw.gpio_set_value(0, 1) elif get_platform_name() == 'digiconnect': self.__xbee_manager.xbee_device_ddo_set_param(None, 'P2', 5, apply=True) self.__xbee_manager.xbee_device_ddo_set_param(None, 'D4', 5, apply=True) digitime.sleep(0.010) for io_pin in range(2): mode = SettingsBase.get_setting( self, 'channel%d_mode' % (io_pin + 1)) mode = self.LOCAL_AIO_MODE_MAP[mode.lower()] if mode == self.LOCAL_AIO_MODE_CURRENTLOOP: self.__xbee_manager.xbee_device_ddo_set_param( None, self.LOCAL_AIO_CONTROL_LINES[io_pin], 2, apply=True) elif mode == self.LOCAL_AIO_MODE_TENV: self.__xbee_manager.xbee_device_ddo_set_param( None, self.LOCAL_AIO_CONTROL_LINES[io_pin], 2, apply=True) if sample[0] == sample[1]: raise ValueError, "Calibration error: equal samples" self.__sample1 = sample[1] self.__sample2 = sample[0] scale1 = self.LOCAL_AIO_CALIBRATION_06 / float(sample[1]) scale2 = self.LOCAL_AIO_CALIBRATION_10 / float(sample[0]) self.__scale = (scale1 + scale2) / 2.0 if self.__OLD_HARDWARE == True: self.__offset = (self.__sample1 * self.__scale - self.LOCAL_AIO_CALIBRATION_06) * 2.4 else: self.__offset = 0.0 else: raise ValueError, "XBee does not support analog inputs" self.__calibration_time = digitime.real_clock() self.__tracer.debug("Scale is %f, offset is %f", self.__scale, self.__offset)