def init_zwave_network(device=None, config_path=None, user_path=None, debug=False): options = ZWaveOption(device, config_path=config_path, user_path=user_path, cmd_line="") options.set_log_file(os.path.join(user_path, "OZW_Log.log")) options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Info') # ('Info' if debug else 'Warning') options.set_logging(True) options.lock() zwave_network = ZWaveNetwork(options, autostart=False) # We connect to the louie dispatcher dispatcher.connect(zwave_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(zwave_network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(zwave_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) return zwave_network
class Open_zwave(HAInterface): VERSION='0.0.1' awake=False ready=False nodesdisplayed=False def __init__(self, *args, **kwargs): self._serialDevicePath = kwargs.get('serialDevicePath', None) self._options = ZWaveOption(self._serialDevicePath, \ config_path="/usr/share/python-openzwave/config", \ user_path=".", cmd_line="") self._options.set_log_file("OZW_Log.log") self._options.set_append_log_file(False) self._options.set_console_output(True) #self._options.set_save_log_level(log) self._options.set_save_log_level('Info') self._options.set_logging(False) self._options.lock() self._network = ZWaveNetwork(self._options, log=None) super(Open_zwave, self).__init__(self, *args, **kwargs) def _init(self, *args, **kwargs): super(Open_zwave, self)._init(self, *args, **kwargs) def _readInterface(self, lastPacketHash): if self._network.state>=self._network.STATE_AWAKED and not self.awake: self.awake = True self._logger.info("Network Awaked") if self._network.state>=self._network.STATE_READY and not self.ready: self.ready = True self._logger.info("Network Ready") if not self.awake: time.sleep(1.0) self._logger.debug("Not awaked") return if self.awake and not self.ready: time.sleep(1.0) self._logger.debug("Not ready") return if not nodesdisplayed: for node in self._network.nodes: print print "------------------------------------------------------------" print "%s - Name : %s" % (self._network.nodes[node].node_id,self._network.nodes[node].name) print "%s - Manufacturer name / id : %s / %s" % (self._network.nodes[node].node_id,self._network.nodes[node].manufacturer_name, self._network.nodes[node].manufacturer_id) print "%s - Product name / id / type : %s / %s / %s" % (self._network.nodes[node].node_id,self._network.nodes[node].product_name, self._network.nodes[node].product_id, self._network.nodes[node].product_type) print "%s - Version : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].version) print "%s - Command classes : %s" % (self._network.nodes[node].node_id,self._network.nodes[node].command_classes_as_string) print "%s - Capabilities : %s" % (self._network.nodes[node].node_id,self._network.nodes[node].capabilities) print "%s - Neigbors : %s" % (self._network.nodes[node].node_id,self._network.nodes[node].neighbors) print "%s - Can sleep : %s" % (self._network.nodes[node].node_id,self._network.nodes[node].can_wake_up()) nodesdisplayed=True def version(self): self._logger.info("Open_zwave Pytomation Driver version " + self.VERSION) self._logger.info("Use openzwave library : %s" % self._network.controller.ozw_library_version) self._logger.info("Use python library : %s" % self._network.controller.python_library_version) self._logger.info("Use ZWave library : %s" % self._network.controller.library_description)
def setup(self, updateCallback): dispatcher.connect(self.onNetworkReady, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self.onNetworkStart, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self.onNetworkFailed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) # TODO: make udev.symlink rule to a specific port (USB0/1) # Uncomment this to run on PC (remember to update the zwave config path) #options = ZWaveOption("/dev/ttyUSB0", \ # config_path="/home/<USER>/software/python-openzwave-0.2.6/openzwave/config", \ options = ZWaveOption("/dev/serial/by-path/platform-bcm2708_usb-usb-0:1.2:1.0-port0", \ config_path="/home/pi/software/python-openzwave-0.2.6/openzwave/config", \ user_path=".", cmd_line="") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Debug') options.set_poll_interval(30); options.set_suppress_value_refresh(False) options.addOptionBool("AssumeAwake", True) options.set_logging(False) options.lock() self.network = ZWaveNetwork(options, autostart=False) self.onDeviceUpdateCallback = updateCallback self.network.start() self.addedConnections = False Timer(2*60, self.setupConnections).start()
def network_init(self): """ Zwave network initialization. Terminate program if initialization failed. """ logging.basicConfig(level=logging.INFO) logger = logging.getLogger('openzwave') # option initialization, abort if initialization failed try: options = ZWaveOption(self.device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") options.set_log_file(self.log_file) options.set_append_log_file(self.write_file) options.set_console_output(self.output_console) options.set_save_log_level(self.log) options.set_logging(False) options.lock() except Exception as e: print( "Zwave initialization failed! \nPlease listen the USB port of zwave stick!" ) print(e) sys.exit(-1) # create a network instance self.network = ZWaveNetwork(options, log=None)
def run(self): """ Run method for the plugin """ self.logger.debug('zwave: run method called') self.alive = True try: options = ZWaveOption(self._device, config_path=self._config_path, user_path='.', cmd_line='') except Exception as e: self.logger.error('zwave: error on create ZWaveOption - {}'.format(e)) self.alive = False return try: options.set_log_file(self._logfile) options.set_save_log_level(self._loglevel) options.set_logging(self._logging) options.set_append_log_file(False) options.set_console_output(False) options.set_security_strategy(self._sec_strategy) options.lock() except Exception as e: self.logger.error('zwave: error on option.set_* - {}'.format(e)) self.logger.debug('zwave: run -> create network') try: self._network = ZWaveNetwork(options, autostart=False) except Exception as e: self.logger.error('zwave: error on create Network Object - {}'.format(e)) self.logger.debug('zwave: run -> connect event handler') try: dispatcher.connect(self.zwave_value_update, ZWaveNetwork.SIGNAL_VALUE_CHANGED) except Exception as e: self.logger.error('zwave: error on connect event handler - {}'.format(e)) self.logger.debug('zwave: run -> start network') try: self._network.start() except Exception as e: self.logger.error('zwave: error on start network - {}'.format(e)) self.logger.info('zwave: use openzwave library: {}'.format(self._network.controller.ozw_library_version)) self.logger.info('zwave: use python library: {}'.format(self._network.controller.python_library_version)) self.logger.info('zwave: use ZWave library: {}'.format(self._network.controller.library_description)) while 1: if self.alive and self._network.state < self._network.STATE_READY: self.logger.debug('zwave: wait until network is ready... current state is: {}'.format(self._network.state_str)) time.sleep(3.0) if self._network.state == self._network.STATE_FAILED: self.alive = false return self.logger.info('zwave: controller ready : {} nodes were found.'.format(self._network.nodes_count)) self.logger.info('zwave: controller node id : {}'.format(self._network.controller.node.node_id)) self.logger.info('zwave: controller node version : {}'.format(self._network.controller.node.version)) self.logger.info('zwave: Network home id : {}'.format(self._network.home_id_str)) self.logger.info('zwave: Nodes in network : {}'.format(self._network.nodes_count))
def __init__(self): ###### options needed for python openzwave library like config files path, logging, device = configpi.interface options = ZWaveOption( device, config_path="/home/pi/IoTLab/python-openzwave/openzwave/config", user_path=".", cmd_line="") options.set_log_file("OZW.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Warning') options.set_logging(True) options.lock() # creation of the object network using the options entity already created self.network = ZWaveNetwork(options, autostart=False) ###### These dispatchers associate a method to a signal. the signals are generated by the library python-openzwave. ###### Once the signal is received. It's associated method is executed (see "_node_added" example below in "_network_started" method) dispatcher.connect(self._network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) ###### backend object attributes # self.devices = OrderedDict() ### will contain the list of nodes in the network # self.sensors = OrderedDict() ### will contain the list of sensors (only) in the network self.node_added = False self.node_removed = False self.timestamps = { } ### will contain the time of the last values' update for each sensor self.queryStages = { ### the diffrent stages that a node object gets through before being ready "None": 1, # Query process hasn't started for this node "ProtocolInfo": 2, # Retrieve protocol information "Probe": 3, # Ping device to see if alive "WakeUp": 4, # Start wake up process if a sleeping node "ManufacturerSpecific1": 5, # Retrieve manufacturer name and product ids if ProtocolInfo lets us "NodeInfo": 6, # Retrieve info about supported, controlled command classes "SecurityReport": 7, # Retrieve a list of Command Classes that require Security "ManufacturerSpecific2": 8, # Retrieve manufacturer name and product ids "Versions": 9, # Retrieve version information "Instances": 10, # Retrieve information about multiple command class instances "Static": 11, # Retrieve static information (doesn't change) "Probe1": 12, # Ping a device upon starting with configuration "Associations": 13, # Retrieve information about associations "Neighbors": 14, # Retrieve node neighbor list "Session": 15, # Retrieve session information (changes infrequently) "Dynamic": 16, # Retrieve dynamic information (changes frequently) "Configuration": 17, # Retrieve configurable parameter information (only done on request) "Complete": 18 # Query process is completed for this node }
def __init__(self, object_group, config): Plugin.__init__(self, config=config, object_group=object_group, plugin_name=PLUGIN_NAME) # Get parameters from the config file if not self.is_enabled(): return # Initialize zwave library # Options try: opts = ZWaveOption( device="/dev/ttyUSB0", config_path= "/home/mlamonta/git/python-openzwave/openzwave/config/", user_path="logs") opts.set_log_file("./logs/zwave.log") opts.set_save_log_level("Alert") opts.set_append_log_file(False) opts.set_console_output(False) opts.set_logging(True) opts.lock() except ZWaveException as e: self.logger.error(str(e)) return # Network self.net = ZWaveNetwork(opts) self.logger.info( "------------------------------------------------------------") self.logger.info("Waiting for network awake : ") self.logger.info( "------------------------------------------------------------") for i in range(0, 300): if self.net.state >= self.net.STATE_AWAKED: self.logger.info("done") break else: time.sleep(1.0) if self.net.state < self.net.STATE_AWAKED: self.logger.warning("Network is not awake") return self.logger.info( "------------------------------------------------------------") for node in self.net.nodes: self.logger.info("%s - %s / %s" % (self.net.nodes[node].node_id, self.net.nodes[node].manufacturer_name, self.net.nodes[node].product_name)) self._initialized = True
def start_zwnetwork(app): options = ZWaveOption(device=app.config['ZWAVE_DEVICE'], config_path=app.config['ZWAVE_DIR'], user_path=app.config['USER_DIR']) options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level(app.config['ZWAVE_DEBUG']) options.set_logging(app.config['ZWAVE_LOGGING']) options.lock() zwnetwork = ZWaveNetwork(options) return zwnetwork
def start_zwnetwork(app): options = ZWaveOption(device=app.config['ZWAVE_DEVICE'], config_path=app.config['ZWAVE_DIR'], user_path=app.config['USER_DIR']) options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level(app.config['ZWAVE_DEBUG']) options.set_logging(app.config['ZWAVE_LOGGING']) options.lock() zwnetwork = ZWaveNetwork(options) return zwnetwork
class TestApi(TestPyZWave): """ Parent test class for api """ @classmethod def setUpClass(self): super(TestApi, self).setUpClass() self.options = ZWaveOption(device=self.device, user_path=self.userpath) self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level("Debug") self.options.set_logging(True) self.options.lock() self.ctrl_command_result = None dispatcher.connect(self.ctrl_message, ZWaveController.SIGNAL_CONTROLLER) self.node_result = None dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) self.network = ZWaveNetwork(self.options) time.sleep(1.0) @classmethod def tearDownClass(self): self.network.stop() time.sleep(2.0) super(TestApi, self).tearDownClass() self.network=None def setUp(self): self.wait_for_network_state(self.network.STATE_AWAKED, 1) def wait_for_queue(self): for i in range(0,60): if self.network.controller.send_queue_count <= 0: break else: time.sleep(0.5) def wait_for_network_state(self, state, multiply=1): for i in range(0,SLEEP*multiply): if self.network.state>=state: break else: #sys.stdout.write(".") #sys.stdout.flush() time.sleep(1.0) def ctrl_message(self, state, message, network, controller): self.ctrl_command_result = state def node_update(self, network, node): self.node_result = node
def __init__(self): ################### instanciation de l'objet backend ######################################################## ###### options needed for python openzwave library like config files path, logging, device = configpi.interface options = ZWaveOption(device, config_path="/home/pi/git-repo/python-openzwave/openzwave/config", user_path=".", cmd_line="") options.set_log_file("OZW.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Warning') options.set_logging(True) options.lock() # creation of the object network using the options entity already created self.network = ZWaveNetwork(options, autostart=False) ###### These dispatchers associate a method to a signal. the signals are generated by the library python-openzwave. ###### Once the signal is reveived. It's associated method is executed (see "_node_added" example below in "_network_started" method) dispatcher.connect(self._network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self._network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) ###### backend object attributes # self.devices = OrderedDict() ### will contain the list of nodes in the network # self.sensors = OrderedDict() ### will contain the list of sensors (only) in the network self.node_added = False self.node_removed = False self.timestamps = {} ### will contain the time of the last values' update for each sensor self.queryStages = { ### the diffrent stages that a node object gets through before being ready "None" : 1, # Query process hasn't started for this node "ProtocolInfo" : 2, # Retrieve protocol information "Probe" : 3, # Ping device to see if alive "WakeUp" : 4, # Start wake up process if a sleeping node "ManufacturerSpecific1" : 5, # Retrieve manufacturer name and product ids if ProtocolInfo lets us "NodeInfo" : 6, # Retrieve info about supported, controlled command classes "SecurityReport" : 7, # Retrieve a list of Command Classes that require Security "ManufacturerSpecific2" : 8, # Retrieve manufacturer name and product ids "Versions" : 9, # Retrieve version information "Instances" : 10, # Retrieve information about multiple command class instances "Static" : 11, # Retrieve static information (doesn't change) "Probe1" : 12, # Ping a device upon starting with configuration "Associations" : 13, # Retrieve information about associations "Neighbors" : 14, # Retrieve node neighbor list "Session" : 15, # Retrieve session information (changes infrequently) "Dynamic" : 16, # Retrieve dynamic information (changes frequently) "Configuration" : 17, # Retrieve configurable parameter information (only done on request) "Complete" : 18 # Query process is completed for this node }
class TestApi(TestPyZWave): """ Parent test class for api """ @classmethod def setUpClass(self): super(TestApi, self).setUpClass() self.options = ZWaveOption(device=self.device, user_path=self.userpath) self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level("Debug") self.options.set_logging(True) self.options.lock() self.network = ZWaveNetwork(self.options) self.ctrl_command_result = None dispatcher.connect(self.ctrl_message, ZWaveController.SIGNAL_CONTROLLER) self.node_result = None dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) @classmethod def tearDownClass(self): self.network.stop() super(TestApi, self).tearDownClass() def setUp(self): self.wait_for_network_state(self.network.STATE_AWAKED, 1) def wait_for_queue(self): for i in range(0, 60): if self.network.controller.send_queue_count <= 0: break else: time.sleep(0.5) def wait_for_network_state(self, state, multiply=1): for i in range(0, SLEEP * multiply): if self.network.state >= state: break else: #sys.stdout.write(".") #sys.stdout.flush() time.sleep(1.0) def ctrl_message(self, state, message, network, controller): self.ctrl_command_result = state def node_update(self, network, node): self.node_result = node
def __init__(self, object_group, config): Plugin.__init__(self, config=config, object_group=object_group, plugin_name=PLUGIN_NAME) # Get parameters from the config file if not self.is_enabled(): return # Initialize zwave library # Options try: opts = ZWaveOption(device="/dev/ttyUSB0", config_path="/home/mlamonta/git/python-openzwave/openzwave/config/", user_path="logs") opts.set_log_file("./logs/zwave.log") opts.set_save_log_level("Alert") opts.set_append_log_file(False) opts.set_console_output(False) opts.set_logging(True) opts.lock() except ZWaveException as e: self.logger.error(str(e)) return # Network self.net = ZWaveNetwork(opts) self.logger.info("------------------------------------------------------------") self.logger.info("Waiting for network awake : ") self.logger.info("------------------------------------------------------------") for i in range(0, 300): if self.net.state >= self.net.STATE_AWAKED: self.logger.info("done") break else: time.sleep(1.0) if self.net.state < self.net.STATE_AWAKED: self.logger.warning("Network is not awake") return self.logger.info("------------------------------------------------------------") for node in self.net.nodes: self.logger.info("%s - %s / %s" % (self.net.nodes[node].node_id, self.net.nodes[node].manufacturer_name, self.net.nodes[node].product_name) ) self._initialized = True
def __init__(self): device = "/dev/ttyUSB0" options = ZWaveOption(device, config_path="/home/rich/openzwave/config", user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Debug') options.set_logging(True) options.lock() self.values = {} dispatcher.connect(self._network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self._network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) self.network = ZWaveNetwork(options, autostart=False)
def __init__(self, device_path, ozw_log_level, logger): self.logger = logger options = ZWaveOption(device_path, config_path="./venv/lib/python3.6/site-packages/python_openzwave/ozw_config", user_path=".", cmd_line="") options.set_log_file("OZW.log") options.set_append_log_file(False) options.set_save_log_level(ozw_log_level) options.set_console_output(False) options.set_logging(True) options.lock() self.options = options self.network = ZWaveNetwork(options, log=None, autostart=False) self.client = InfluxDBClient(database=DATABASE)
class TestNetworkStartStop(TestPyZWave): @classmethod def setUpClass(self): super(TestNetworkStartStop, self).setUpClass() self.options = None self.network = None @classmethod def tearDownClass(self): if self.network is not None: self.network.stop() super(TestNetworkStartStop, self).tearDownClass() def test_000_network_start_stop(self): self.driver_ready = False self.driver_removed = False self.options = ZWaveOption(device=self.device, user_path=self.userpath) self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level("Debug") self.options.set_logging(True) self.options.lock() dispatcher.connect(self.driver_ready_message, ZWaveNetwork.SIGNAL_DRIVER_READY) dispatcher.connect(self.driver_removed_message, ZWaveNetwork.SIGNAL_DRIVER_REMOVED) self.network = ZWaveNetwork(self.options) for i in range(0, SLEEP): if self.network.state>=self.network.STATE_AWAKED: break else: time.sleep(1.0) self.assertTrue(self.driver_ready) self.network.stop() for i in range(0, SLEEP): if self.network.state==self.network.STATE_STOPPED: break else: time.sleep(1.0) self.assertEqual(self.network.state, self.network.STATE_STOPPED) #self.assertTrue(self.driver_removed) self.network = None def driver_ready_message(self, network, controller): self.driver_ready = True def driver_removed_message(self, network): self.driver_removed = True
def _init_openzwave(self, zwave_device, zwave_config_path, zwave_user_path): """Initialise the OpenZWave client, leaving it ready to start.""" # Configure OpenZWave options = ZWaveOption(zwave_device, config_path=zwave_config_path, user_path=zwave_user_path, cmd_line="") options.set_log_file(os.path.join(zwave_user_path, "zwave.log")) options.set_append_log_file(True) options.set_console_output(True) options.set_save_log_level("Warning") options.set_logging(True) options.lock() self._ozw_network = ZWaveNetwork(options, autostart=False)
def log_level(self): self.logger.info("Performing log level entries") options = ZWaveOption( device, config_path="/home/riaps/python-openzwave/openzwave/config", user_path=".", cmd_line="") options.set_log_file("OZW.log") options.set_append_log_file(False) options.set_save_log_level("Info") options.set_console_output(False) options.set_logging(True) options.lock() self.ZWaveOption = options self.network = ZWaveNetwork(options, log=None, autostart=False) self.logger.info("log level entries done")
def init(): log.info("initializing...") global _network #Define some manager options options = ZWaveOption(config.ZWAVE_DEVICE, config_path=config.OPENZWAVE_CONFIG_FILE, user_path=".", cmd_line="") options.set_log_file(config.OPENZWAVE_LOG_FILE) options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level(config.OPENZWAVE_LOG_LEVEL) #options.set_save_log_level('Info') options.set_logging(True) options.lock() #Create a network object _network = ZWaveNetwork(options)
def init_zwave_network(device=None, config_path=None, user_path=None, debug=False): options = ZWaveOption(device, config_path=config_path, user_path=user_path, cmd_line="") options.set_log_file(os.path.join(user_path, "OZW_Log.log")) options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Info') # ('Info' if debug else 'Warning') options.set_logging(True) options.lock() zwave_network = ZWaveNetwork(options, autostart=False) # We connect to the louie dispatcher dispatcher.connect(zwave_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(zwave_network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(zwave_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) return zwave_network
def connect(self) -> None: options = ZWaveOption( self.__zwave_config.port, config_path=self.__zwave_config.openzwave_config_path, user_path=".", cmd_line="") options.set_console_output(False) options.set_save_log_level("None") options.set_logging(False) options.lock() self.__network = ZWaveNetwork(options, autostart=False) dispatcher.connect(self.__network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self.__network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self.__value_update, ZWaveNetwork.SIGNAL_VALUE) self.__network.start()
def __init__(self): #super(, self).__init__() options = ZWaveOption(device, \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(True) options.set_save_log_level(log) #options.set_save_log_level('Info') options.set_logging(False) options.lock() self._optiton = options self.network = ZWaveNetwork(options, log=None) time_started = 0 for i in range(0,100): if self.network.state>=self.network.STATE_AWAKED: break else: time_started += 1 time.sleep(1.0) if self.network.state<self.network.STATE_AWAKED: print("Network is not awake but continue anyway") for i in range(0,300): if self.network.state>=self.network.STATE_READY: print("home ID {}".format(home_id)) break else: sys.stdout.write(".") time_started += 1 #sys.stdout.write(network.state_str) #sys.stdout.write("(") #sys.stdout.write(str(network.nodes_count)) #sys.stdout.write(")") #sys.stdout.write(".") sys.stdout.flush() time.sleep(1.0) if not network.is_ready: print("network is not ready but start anyway") network.start() self.controller = network.controller
def init_zwave(device,config_path): #device ="/dev/ttyUSB0" log="None" #Define some manager options options = ZWaveOption(device, \ config_path=config_path, user_path=config_path, cmd_line="") #config_path=str(os.getcwd())+"/../../packages/python-openzwave/openzwave/config", \ options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(True) options.set_save_log_level('Info') options.set_logging(False) options.lock() #Create a network object network = ZWaveNetwork(options, autostart=True) dispatcher.connect(louie_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) return network
def __init__(self, device_path, ozw_log_level, logger): self.logger = logger options = ZWaveOption( device_path, config_path= "./venv/lib/python3.%d/site-packages/python_openzwave/ozw_config" % sys.version_info[1], user_path=".", cmd_line="") options.set_log_file("OZW.log") options.set_append_log_file(False) options.set_save_log_level(ozw_log_level) options.set_console_output(False) options.set_logging(True) options.lock() self.options = options self.network = ZWaveNetwork(options, log=None, autostart=False) self.csvfile = open('output.csv', 'a') self.writer = csv.writer(self.csvfile) self.stopping = False
def _init(self, device, config, timeout): self.network = None self.status = 1 self.timeout = timeout self.device = device self.config = config options = ZWaveOption(self.device, config_path=self.config, user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Debug') options.set_logging(True) options.lock() self.network = ZWaveNetwork(options, autostart=False) dispatcher.connect(louie_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(louie_network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) self.network.start()
def setup(self): self.logs = myLogs('zwave-daemon') device = "/dev/ttyUSB0" log = "Info" # Debug #Define some manager options # see docs at the end of file options = ZWaveOption(device, \ #config_path="openzwave/config", \ user_path="/home/scripts/zwave/home",\ cmd_line="" ) #options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('None') #options.set_queue_log_level("None") #options.set_save_log_level('Info') options.set_logging(False) options.lock() self.ZWave = ZWaveNetwork(options, log=None, autostart=False)
def __init__( self ): device="/dev/ttyUSB0" options = ZWaveOption( "/dev/ttyUSB0", \ config_path=os.path.expanduser("~/.zwave/config/"), \ #user_path='.', \ user_path=os.path.expanduser("~/.zwave/"), \ cmd_line="") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Info') options.set_logging(True) options.lock() print "Initialize Z-Wave network" self.network = ZWaveNetwork(options, log=None) print "Wait for driver" # Waiting for driver for i in range(0,20): if self.network.state>=self.network.STATE_INITIALISED: break else: time.sleep(1.0) if self.network.state<self.network.STATE_INITIALISED: print "Can't initialise driver! Look at the logs in OZW_Log.log" quit(1) print "Wait for network ready" # Waiting for network ready for i in range(0,90): if self.network.state>=self.network.STATE_READY: break else: time.sleep(1.0) if not self.network.is_ready: print "Can't start network! Look at the logs in OZW_Log.log" quit(2)
class Open_zwave(HAInterface): VERSION = '0.0.4' def louie_network_ready(self, network): self._logger.info(">>>>>>> Hello from network : I'm ready : %d nodes were found.".format(self._network.nodes_count)) self._logger.info(">>>>>>> Hello from network : my controller is : {}".format(self._network.controller)) dispatcher.connect(self.louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(self.louie_value_update, ZWaveNetwork.SIGNAL_VALUE) def louie_node_update(self, network, node): self._logger.debug('>>>>>>> Hello from node : {}.'.format(node)) def louie_value_update(self, network, node, value): self._logger.debug('>>>>>>> Hello from value : {}'.format(value)) for lockvalue in self.get_door_locks(node.node_id).values(): if lockvalue.value_id == value.value_id: if value.data: self._onCommand(address=str(node.node_id), command=Command.LOCK) else: self._onCommand(address=str(node.node_id), command=Command.UNLOCK) for val in self._network.nodes[node.node_id].get_switches(): if val == value.value_id: if value.data: self._onCommand(address=str(node.node_id), command=Command.ON) else: self._onCommand(address=str(node.node_id), command=Command.OFF) for val in self._network.nodes[node.node_id].get_dimmers() : if val == value.value_id: #Poll dimmer to ensure ramp up/down completes level = value.data if self.dimmer_polled_value.has_key(val): self._logger.debug('>>>>>>> Hello from level : {} {}'.format(level, self.dimmer_polled_value[val])) if level == self.dimmer_polled_value[val]: del self.dimmer_polled_value[val] if level < 2: self._onCommand(address=str(node.node_id), command=Command.OFF) elif level > 98: self._onCommand(address=str(node.node_id), command=Command.ON) else: self._onCommand(address=str(node.node_id), command=(Command.LEVEL,level)) else: self.dimmer_polled_value[val] = level time.sleep(1) value.refresh() else: time.sleep(1) self.dimmer_polled_value[val] = level value.refresh() def __init__(self, *args, **kwargs): self._serialDevicePath = kwargs.get('serialDevicePath', None) self._configpath = kwargs.get('config_path', "/etc/openzwave/") super(Open_zwave, self).__init__(self, *args, **kwargs) self.dimmer_polled_value = {} def _init(self, *args, **kwargs): self.awake = False self.ready = False self.nodesdisplayed = False self._options = ZWaveOption(self._serialDevicePath, \ config_path=self._configpath, \ user_path=".", cmd_line="") self._options.set_log_file("OZW_Log.log") self._options.set_append_log_file(False) self._options.set_console_output(False) #self._options.set_save_log_level(log) self._options.set_save_log_level('Info') self._options.set_logging(True) self._options.set_notify_transactions(True) self._options.lock() self._network = ZWaveNetwork(self._options, log=None,autostart=False) dispatcher.connect(self.louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) self._network.start() super(Open_zwave, self)._init(self, *args, **kwargs) def _printNetwork(self, node): node = self._network.nodes[node] self._logger.info("------------------------------------------------------") self._logger.info("{} - Name : {}".format(node.node_id, node.name)) self._logger.info("{} - Manufacturer name / id : {} / {}".format( node.node_id, node.manufacturer_name, node.manufacturer_id)) self._logger.info("{} - Product name / id / type : {} / {} / {}".format( node.node_id, node.product_name, node.product_id, node.product_type)) self._logger.info("{} - Version : {}".format(node.node_id, node.version)) self._logger.info("{} - Command classes : {}".format(node.node_id, node.command_classes_as_string)) self._logger.info("{} - Capabilities : {}".format(node.node_id, node.capabilities)) self._logger.info("{} - Neighbors : {}".format(node.node_id, node.neighbors)) self._logger.info("{} - Can sleep : {}".format(node.node_id, node.can_wake_up())) for value in self.get_door_locks(node.node_id, 'All').values(): self._logger.debug("{} - {} : {}".format(node.node_id,value.label,value.data)) def _readInterface(self, lastPacketHash): if (self._network.state >= self._network.STATE_AWAKED and not self.awake): self.awake = True self._logger.info("Network Awaked") if (self._network.state >= self._network.STATE_READY and not self.ready): self.ready = True self._logger.info("Network Ready") if not self.awake: self._logger.debug("Not awaked") elif self.awake and not self.ready: self._logger.debug("Not ready") elif not self.nodesdisplayed and self.ready: for node in self._network.nodes: self._printNetwork(node) self.update_status() self.nodesdisplayed = True time.sleep(1) def version(self): self._logger.info("Open_zwave Pytomation Driver version " + self.VERSION) self._logger.info("Use openzwave library : {}".format(self._network.controller.ozw_library_version)) self._logger.info("Use python library : {}".format(self._network.controller.python_library_version)) self._logger.info("Use ZWave library : {}".format(self._network.controller.library_description)) def get_door_locks(self, node, datatype = 'Bool'): return self._network.nodes[node].get_values(class_id=0x62, genre='User', \ type=datatype, readonly=False, writeonly=False) def lock(self, address): node = int(address) for value in self.get_door_locks(node).values(): self._logger.debug("Lock") value.data = True def unlock(self, address): node = int(address) for value in self.get_door_locks(node).values(): self._logger.debug("Unlock") value.data = False def on(self, address): node = int(address) for val in self._network.nodes[node].get_switches() : self._logger.debug("Activate switch") self._network.nodes[node].set_switch(val,True) for val in self._network.nodes[node].get_dimmers() : self._logger.debug("Activate dimmer : {}".format(self._network.nodes[node])) self._network.nodes[node].set_dimmer(val,99) def off(self, address): node = int(address) for val in self._network.nodes[node].get_switches() : self._logger.debug("Deactivate switch") self._network.nodes[node].set_switch(val,False) for val in self._network.nodes[node].get_dimmers() : self._logger.debug("Deactivate dimmer : {}".format(self._network.nodes[node])) self._network.nodes[node].set_dimmer(val,0) def level(self, address, level): node = int(address) for val in self._network.nodes[node].get_dimmers() : self._logger.debug("Set dimmer : {}".format(self._network.nodes[node])) self._network.nodes[node].set_dimmer(val, level) def status(self, address): node = int(address) for val in self._network.nodes[node].get_switches() : level = self._network.nodes[node].get_switch_state(val) if level: self._onState(address=address, state=State.ON) else: self._onState(address=address, state=State.OFF) for val in self._network.nodes[node].get_dimmers() : level = self._network.nodes[node].get_dimmer_level(val) if level < 2: self._onState(address=address, state=State.OFF) elif level > 98: self._onState(address=address, state=State.ON) else: self._onState(address=address, state=(State.LEVEL,level)) for value in self.get_door_locks(node).values(): if value.data: self._onState(address=address, state=State.LOCKED) else: self._onState(address=address, state=State.UNLOCKED) def update_status(self): for d in self._devices: self.status(d.address)
class TestApi(TestPyZWave): """ Parent test class for api """ @classmethod def setUpClass(self): super(TestApi, self).setUpClass() self.options = ZWaveOption(device=self.device, user_path=self.userpath) self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(self.ozwout) self.options.set_save_log_level(self.ozwlog) self.options.set_logging(True) self.options.lock() self.node_result = None dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) self.network = ZWaveNetwork(self.options) self.ctrl_command_result = None self.ctrl_command_signal = None #dispatcher.connect(self.ctrl_message, ZWaveNetwork.SIGNAL_CONTROLLER_COMMAND) time.sleep(1.0) @classmethod def tearDownClass(self): self.network.stop() time.sleep(2.0) self.network.destroy() time.sleep(1.0) super(TestApi, self).tearDownClass() self.network = None def setUp(self): self.wait_for_network_state(self.network.STATE_AWAKED, 1) def wait_for_queue(self): for i in range(0,60): if self.network.controller.send_queue_count <= 0: break else: time.sleep(0.5) def wait_for_network_state(self, state, multiply=1): for i in range(0,SLEEP*multiply): if self.network.state>=state: break else: time.sleep(1.0) def ctrl_message(self, network, controller, node, node_id, state_int, state, state_full, error_int, error, error_full,): self.ctrl_state_result = state self.ctrl_command_signal = { 'network':network, 'controller':controller, 'node':node, 'node_id':node_id, 'state_int':state_int, 'state':state, 'state_full':state_full, 'error_int':error_int, 'error':error, 'error_full':error_full, } def ctrl_waiting(self, network, controller, state_int, state, state_full): self.ctrl_state_result = state def node_update(self, network, node): self.node_result = node
import time device="/dev/zwave-aeon-s2" for arg in sys.argv: if arg.startswith("--device"): temp,device = arg.split("=") #Define some manager options options = ZWaveOption(device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Debug') #options.set_save_log_level('Info') options.set_logging(True) options.lock() #Create a network object network = ZWaveNetwork(options, log=None) print "------------------------------------------------------------" print "Waiting for driver : " print "------------------------------------------------------------" for i in range(0,20): if network.state>=network.STATE_INITIALISED: print " done" break else:
def __init__(self, **kwargs): """Attrs initialized here have names as in :dict:`_initials` Doctests ++++++++ >>> t.start() (True, 'OK') # >>> t.hard_reset(force=True) # (True, 'OK') # >>> print("*** Action needed for node to be _added_ ***") # doctest:+ELLIPSIS # *** ... # >>> t.add_node() # doctest:+ELLIPSIS # {...} """ if self._initialized: raise RuntimeErr("[Bug] backend already initialized!?") self._initialized = True # set defaults for attr in self._initials.keys(): setattr(self, attr, self._initials[attr]) # ...remainder. for k in kwargs.keys(): if not hasattr(self, k): raise AttributeError( "{}: no such attribute in definition of class {}.".format( k, self.__class__.__name__)) else: setattr(self, k, kwargs[k]) # we put all artifacts here user_path = os.path.expanduser(os.path.expandvars(self.ozw_user_path)) try: os.makedirs(self.ozw_user_path, exist_ok=True) except Exception as e: raise RuntimeError("Can't create user_path: {}".format(e)) self.logger = logging.getLogger(__name__) self.logger.setLevel(self.log_level) fh = logging.FileHandler("{}/{}.log".format(self.ozw_user_path, __name__), mode='w') fh.setLevel(self.log_level) fh.setFormatter( logging.Formatter(self.log_format_dbg if self.log_level <= logging. DEBUG else self.log_format)) self.logger.addHandler(fh) self.logger.debug('initializing OZW backend...') options = ZWaveOption(self.device, config_path=self.ozw_config_path, user_path=self.ozw_user_path) options.set_log_file('OZW.log') options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level( 'Debug' if self.log_level <= logging.DEBUG else 'Warning') options.set_logging(True) options.lock() self.network = ZWaveNetwork(options, autostart=False) # A dispatcher associates a callback method to a signal. Signals # are generated by the library python-openzwave. Once a signal is # received, its associated callback is executed (see "_node_added" # example below in "_network_started" method) dispatcher.connect(self._network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) # Yep! It's really 'RESETTED', wanna file a bug for bad english usage? ;-) dispatcher.connect(self._network_reset, ZWaveNetwork.SIGNAL_NETWORK_RESETTED) # dynamically set on add/remove events. See notification handlers below. self.node_added = None self.node_removed = None self.timestamps = { } # times of the last values' update for each sensor # The different stages that a node object gets through before being # ready. [BUG] Why do we need to explicitly list them? Anyway to get # them from the lib? self.queryStages = { "None": 1, # Query process hasn't started for this node "ProtocolInfo": 2, # Retrieve protocol information "Probe": 3, # Ping node to see if alive "WakeUp": 4, # Start wake up process if a sleeping node "ManufacturerSpecific1": 5, # Retrieve manufacturer name and product ids if ProtocolInfo lets us "NodeInfo": 6, # Retrieve info about supported, controlled command classes "NodePlusInfo": 7, # Retrieve Z-Wave+ info and update device classes (Added by Edin et Daniel) "SecurityReport": 8, # Retrieve a list of Command Classes that require Security "ManufacturerSpecific2": 9, # Retrieve manufacturer name and product ids "Versions": 10, # Retrieve version information "Instances": 11, # Retrieve information about multiple command class instances "Static": 12, # Retrieve static information (doesn't change) "Probe1": 13, # Ping a node upon starting with configuration "Associations": 14, # Retrieve information about associations "Neighbors": 15, # Retrieve node neighbor list "Session": 16, # Retrieve session information (changes infrequently) "Dynamic": 17, # Retrieve dynamic information (changes frequently) "Configuration": 18, # Retrieve configurable parameter information (only done on request) "Complete": 19 # Query process is completed for this node }
elif arg.startswith("--log"): temp,log = arg.split("=") elif arg.startswith("--help"): print("help : ") print(" --device=/dev/yourdevice ") print(" --log=Info|Debug") print "----------------------------------------------------------------------" print "Waiting for network : " options = ZWaveOption(device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level("Debug") options.set_logging(True) options.lock() network = ZWaveNetwork(options, log=None) for i in range(0,300): if network.state>=network.STATE_AWAKED: break else: sys.stdout.write(".") sys.stdout.flush() time.sleep(1.0) print "" print "Awake" ready = False for i in range(0,300): if network.state>=network.STATE_READY:
class TestApi(TestPyZWave): """ Parent test class for api """ @classmethod def setUpClass(self): super(TestApi, self).setUpClass() self.options = ZWaveOption(device=self.device, user_path=self.userpath) self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(self.ozwout) self.options.set_save_log_level(self.ozwlog) self.options.set_logging(True) self.options.lock() dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) self.network = ZWaveNetwork(self.options) self.node_result = None self.ctrl_command_result = None self.ctrl_command_signal = None #dispatcher.connect(self.ctrl_message, ZWaveNetwork.SIGNAL_CONTROLLER_COMMAND) time.sleep(1.0) @classmethod def tearDownClass(self): self.network.stop() time.sleep(2.0) self.network.destroy() time.sleep(1.0) super(TestApi, self).tearDownClass() self.network = None def setUp(self): self.node_result = None self.ctrl_command_result = None self.ctrl_command_signal = None self.wait_for_network_state(self.network.STATE_AWAKED, 1) time.sleep(1.0) self.wait_for_queue() self.active_nodes = {} for node in self.network.nodes: if self.network.nodes[node].is_info_received: self.active_nodes[node] = self.network.nodes[node] print('active nodes : %s' % self.active_nodes) def wait_for_queue(self): for i in range(0, 60): if self.network.controller.send_queue_count <= 0: break else: time.sleep(0.5) def wait_for_network_state(self, state, multiply=1): for i in range(0, SLEEP * multiply): if self.network.state >= state: break else: time.sleep(1.0) def ctrl_message( self, network, controller, node, node_id, state_int, state, state_full, error_int, error, error_full, ): self.ctrl_state_result = state self.ctrl_command_signal = { 'network': network, 'controller': controller, 'node': node, 'node_id': node_id, 'state_int': state_int, 'state': state, 'state_full': state_full, 'error_int': error_int, 'error': error, 'error_full': error_full, } def ctrl_waiting(self, network, controller, state_int, state, state_full): self.ctrl_state_result = state def node_update(self, network, node): self.node_result = node
class AlidronOZW(object): def __init__(self, device, isac_node): self.isac_node = isac_node self.signals = {} self._ozw_notif_queue = Queue() self._running = True green.spawn(self._notif_reader) self.options = ZWaveOption( device, config_path='/usr/share/openzwave/config', user_path='./user-dir', cmd_line='' ) self.options.set_log_file("./user-dir/OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level('Info') self.options.set_logging(False) self.options.lock() self.network = ZWaveNetwork(self.options, log=None) notif_to_func = [ (ZWaveNetwork.SIGNAL_NETWORK_STARTED, self.notif_network_started), (ZWaveNetwork.SIGNAL_NETWORK_RESETTED, self.notif_network_resetted), (ZWaveNetwork.SIGNAL_NETWORK_READY, self.notif_network_ready), (ZWaveNetwork.SIGNAL_NODE_ADDED, self.notif_node_added), (ZWaveNetwork.SIGNAL_NODE_NAMING, self.notif_node_named), (ZWaveNetwork.SIGNAL_NODE_REMOVED, self.notif_node_removed), (ZWaveNetwork.SIGNAL_VALUE_ADDED, self.notif_value_added), (ZWaveNetwork.SIGNAL_VALUE_CHANGED, self.notif_value_update), (ZWaveNetwork.SIGNAL_VALUE_REMOVED, self.notif_value_removed), (ZWaveNetwork.SIGNAL_CONTROLLER_COMMAND, self.notif_ctrl_message), (ZWaveNetwork.SIGNAL_CONTROLLER_WAITING, self.notif_ctrl_message), ] for notif, func in notif_to_func: dispatcher.connect(self._notif_wrapper(func), notif, weak=False) # dispatcher.connect(self._notif_wrapper_all, All) self.isac_node.add_rpc(self.network_heal) self.isac_node.add_rpc(self.controller_add_node, name='add_node') self.isac_node.add_rpc(self.controller_remove_node, name='remove_node') self.isac_node.add_rpc(self.controller_cancel_command, name='cancel_command') # Plumbing def _notif_wrapper(self, f): def _notif(*args, **kwargs): logger.debug('Received notification for %s with args %s and kwargs %s', f.__name__, args, kwargs) del kwargs['signal'] del kwargs['sender'] self._ozw_notif_queue.put((f, args, kwargs)) return _notif def _notif_wrapper_all(self, *args, **kwargs): del kwargs['sender'] self._ozw_notif_queue.put((self.all_notif, args, kwargs)) def _notif_reader(self): while self._running: notif = self._ozw_notif_queue.get() if notif is None: continue f, args, kwargs = notif logger.debug('Reading notification for %s with args %s and kwargs %s', f.__name__, args, kwargs) f(*args, **kwargs) def all_notif(self, *args, **kwargs): import time from pprint import pformat as pf extra = [] if 'value' in kwargs and kwargs['value']: extra.append('value: %s' % self._make_uri(kwargs['node'], kwargs['value'])) elif 'node' in kwargs and kwargs['node']: extra.append('node: %s' % (kwargs['node'].name if kwargs['node'].name else kwargs['node'].node_id)) extra = ' ; '.join(extra) if args: logger.warning('>~>~># %f: %s ; %s ; %s', time.time(), pf(args), pf(kwargs), extra) else: logger.warning('>~>~># %f: %s ; %s', time.time(), pf(kwargs), extra) # Notifications from PYOZW def notif_network_started(self, network): logger.info('//////////// ZWave network is started ////////////') logger.debug( 'OpenZWave network is started: \ homeid %0.8x - %d nodes were found.', network.home_id, network.nodes_count ) def notif_network_resetted(self, network): logger.warning('OpenZWave network is resetted.') def notif_network_ready(self, network): logger.info('//////////// ZWave network is ready ////////////') logger.debug( 'ZWave network is ready: %d nodes were found.', network.nodes_count ) def notif_node_added(self, network, node): node_name = self._node_name(node) logger.info('Node added: %s.', node_name) self.isac_node.add_rpc(partial(self.node_heal, node), '%s/heal' % node_name) self.isac_node.add_rpc(partial(self.node_is_failed, node), '%s/is_failed' % node_name) def notif_node_named(self, network, node): logger.info('Node named: %s.', self._node_name(node)) # TODO: renaming of RPC enpoints as well as all IsacValue attached to the node, if the name really changed def notif_node_removed(self, network, node): logger.info('Node removed: %s.', self._node_name(node)) # TODO: Remove RPC endpoint (values should be removed by receiving VALUE_REMOVED notif) def notif_value_added(self, network, node, value): uri = self._make_uri(node, value) if uri in self.signals: logger.info('%s already registered', uri) return else: logger.info('Registering signal %s', uri) self.signals[uri] = { 'metadata': { 'uri': uri, 'label': value.label, 'help': value.help, 'max': value.max, 'min': value.min, 'units': value.units, 'genre': value.genre, 'type': value.type, 'is_read_only': value.is_read_only, 'is_write_only': value.is_write_only, 'instance': value.instance, 'index': value.index, 'value_id': value.value_id, 'node_id': node.node_id, 'node_name': node.name, 'location': node.location, 'home_id': node._network.home_id, 'command_class': node.get_command_class_as_string(value.command_class), 'data_items': list(value.data_items) if type(value.data_items) is set else value.data_items, }, 'static_tags': { 'home_id': node._network.home_id, 'location': node.location, 'node_id': node.node_id, 'command_class': node.get_command_class_as_string(value.command_class), 'index': value.index, 'instance': value.instance, }, 'node_value': (node, value), } data = self._value_data(value) #print '>>>> Creating IV', uri, data self.signals[uri]['isac_value'] = IsacValue( self.isac_node, uri, data, static_tags=self.signals[uri]['static_tags'], metadata=self.signals[uri]['metadata'], survey_last_value=False, survey_static_tags=False ) self.signals[uri]['isac_value'].observers += self._update_data_from_isac uri_poll = uri + '/poll' self.signals[uri_poll] = { 'isac_value': IsacValue( self.isac_node, uri_poll, value.is_polled, survey_last_value=False, survey_static_tags=False ), 'node_value': self.signals[uri]['node_value'], } self.signals[uri_poll]['isac_value'].observers += self._set_poll_from_isac def notif_value_update(self, network, node, value): uri = self._make_uri(node, value) logger.info('Value update for %s : %s.', uri, value.data) if uri not in self.signals: logger.info('%s not yet registered, skipping', uri) return signal = self.signals[uri] signal['isac_value'].value = self._value_data(value) def notif_value_removed(self, network, node, value): pass # TODO: Remove IsacValue def notif_ctrl_message(self, network, controller, **kwargs): # from pprint import pformat as pf # logger.warning('Controller message : %s', pf(kwargs)) pass # Update from ISAC def _update_data_from_isac(self, isac_value, value, ts, tags): uri = isac_value.uri signal = self.signals.get(uri, None) if signal is None: logger.error( 'Received an update from isac \ for a signal we don\'t know?! %s', uri ) return if signal['node_value'][1].is_read_only: logger.error( 'Signal %s is read only but we received an update \ from isac to write a value, %s, to it', uri, value ) return logger.info('Updating value %s with %s', uri, value) signal['node_value'][1].data = value def _set_poll_from_isac(self, isac_value, value, ts, tags): uri = isac_value.uri signal = self.signals.get(uri, None) if signal is None: logger.error('Signal %s is unknown?!', uri) return if uri.endswith('/poll'): if bool(value): try: intensity = int(value) except ValueError: intensity = 1 signal['node_value'][1].enable_poll(intensity) else: signal['node_value'][1].disable_poll() # RPC methods # controller: (hard_reset) has_node_failed(nodeid) name remove_failed_node(nodeid) replace_failed_node(nodeid) (soft_reset) # node: location name # def has_node_failed(self, node_name): # from pprint import pprint as pp # nodes_by_name = {node.name: node for node in self.network.nodes.values()} # pp(nodes_by_name) # node_id = nodes_by_name[node_name].node_id # # print nodes_by_name[node_name].is_failed # return self.network.controller.has_node_failed(node_id) def network_heal(self, upNodeRoute=False): logger.info('Healing network') self.network.heal(upNodeRoute) def controller_add_node(self, doSecurity=False): logger.info('Set controller into inclusion mode') return self.network.controller.add_node(doSecurity) def controller_remove_node(self): logger.info('Set controller into exclusion mode') return self.network.controller.remove_node() def controller_cancel_command(self): logger.info('Cancelling controller command') return self.network.controller.cancel_command() def node_heal(self, node, upNodeRoute=False): logger.info('Healing node %s', self._node_name(node)) return node.heal(upNodeRoute) def node_is_failed(self, node): logger.info('Asking if node %s is failed (%s)', self._node_name(node), node.is_failed) return node.is_failed # Tooling @staticmethod def _replace_all(s, olds, new): return reduce(lambda s, old: s.replace(old, new), list(olds), s) def _node_name(self, node): return node.name if node.name else str(node.node_id) def _value_data(self, value): data = value.data logger.debug('data type is %s', type(data)) if type(data) is str: try: data.decode() except UnicodeDecodeError: data = binascii.b2a_base64(data) return data def _make_uri(self, node, value): def _values_by_index(values): per_idx = {} for value in values: idx = value.index if idx not in per_idx: per_idx[idx] = [] per_idx[idx].append(value) return per_idx ok = False while not ok: try: values_by_idx = _values_by_index(node.get_values(class_id=value.command_class).values()) ok = True except RuntimeError as ex: if ex.message == 'dictionary changed size during iteration': continue else: raise is_multi_instance = len(values_by_idx[value.index]) > 1 cmd_class = node.get_command_class_as_string(value.command_class) cmd_class = cmd_class.replace('COMMAND_CLASS_', '').lower() node_name = self._node_name(node) label = self._replace_all(value.label.lower(), ' /()%:', '_').strip('_') if is_multi_instance: uri = 'zwave://%s.%s/%s/%d/%s' % ( node._network.home_id_str, node_name, cmd_class, value.instance, label) else: uri = 'zwave://%s.%s/%s/%s' % ( node._network.home_id_str, node_name, cmd_class, label) return str(uri) # Lifecycle def shutdown(self): # Stopping internal notification reader greenlet self._running = False self._ozw_notif_queue.put(None) self.network.stop() logger.info('Stopped network') self.network.destroy() logger.info('Destroyed network') self.isac_node.shutdown() logger.info('Stopped ISAC node')
class Open_zwave(HAInterface): VERSION = '0.0.2' awake = False ready = False nodesdisplayed = False def louie_network_ready(network): self._logger.info(">>>>>>> Hello from network : I'm ready : %d nodes were found." % self._network.nodes_count) self._logger.info(">>>>>>> Hello from network : my controller is : %s" % self._network.controller) dispatcher.connect(self.louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(self.louie_value_update, ZWaveNetwork.SIGNAL_VALUE) def louie_node_update(network, node): self._logger.info('>>>>>>> Hello from node : %s.' % node) def louie_value_update(network, node, value): self._logger.info('>>>>>>> Hello from value : %s.' % value) def __init__(self, *args, **kwargs): self._serialDevicePath = kwargs.get('serialDevicePath', None) self._options = ZWaveOption(self._serialDevicePath, \ config_path="/usr/local/etc/openzwave/", \ user_path=".", cmd_line="") self._options.set_log_file("OZW_Log.log") self._options.set_append_log_file(False) self._options.set_console_output(False) #self._options.set_save_log_level(log) self._options.set_save_log_level('Info') self._options.set_logging(True) self._options.set_notify_transactions(True) self._options.lock() self._network = ZWaveNetwork(self._options, log=None,autostart=False) dispatcher.connect(self.louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) self._network.start() super(Open_zwave, self).__init__(self, *args, **kwargs) def _printNetwork(self, node): print print "------------------------------------------------------" print "%s - Name : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].name) print "%s - Manufacturer name / id : %s / %s" % ( self._network.nodes[node].node_id, self._network.nodes[node].manufacturer_name, self._network.nodes[node].manufacturer_id) print "%s - Product name / id / type : %s / %s / %s" % ( self._network.nodes[node].node_id, self._network.nodes[node].product_name, self._network.nodes[node].product_id, self._network.nodes[node].product_type) print "%s - Version : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].version) print "%s - Command classes : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].command_classes_as_string) print "%s - Capabilities : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].capabilities) print "%s - Neighbors : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].neighbors) print "%s - Can sleep : %s" % (self._network.nodes[node].node_id, self._network.nodes[node].can_wake_up()) def _init(self, *args, **kwargs): super(Open_zwave, self)._init(self, *args, **kwargs) def _readInterface(self, lastPacketHash): if (self._network.state >= self._network.STATE_AWAKED and not self.awake): self.awake = True self._logger.info("Network Awaked") if (self._network.state >= self._network.STATE_READY and not self.ready): self.ready = True self._logger.info("Network Ready") self._logger.info("********************************* NETWORK READY ************************************") if not self.awake: time.sleep(1.0) self._logger.debug("Not awaked") return if self.awake and not self.ready: time.sleep(1.0) self._logger.debug("Not ready") return if not self.nodesdisplayed and self.ready: for node in self._network.nodes: self._printNetwork(node) self.nodesdisplayed = True time.sleep(1) def version(self): self._logger.info("Open_zwave Pytomation Driver version " + self.VERSION) self._logger.info("Use openzwave library : %s" % self._network.controller.ozw_library_version) self._logger.info("Use python library : %s" % self._network.controller.python_library_version) self._logger.info("Use ZWave library : %s" % self._network.controller.library_description) def on(self, address): node = int(address) for val in self._network.nodes[node].get_switches() : self._logger.info("Activate switch") self._network.nodes[node].set_switch(val,True) for val in self._network.nodes[node].get_dimmers() : self._logger.info("Activate dimmer : %s" % self._network.nodes[node]) self._network.nodes[node].set_dimmer(val,99) def off(self, address): node = int(address) for val in self._network.nodes[node].get_switches() : self._logger.info("Activate switch") self._network.nodes[node].set_switch(val,False) for val in self._network.nodes[node].get_dimmers() : self._logger.info("Activate dimmer : %s" % self._network.nodes[node]) self._network.nodes[node].set_dimmer(val,0) def status(self, address): node = int(address) for val in self._network.nodes[node].get_dimmers() : level = self._network.nodes[nodeid].get_dimmer_level(val)
from pydispatch import dispatcher else: from louie import dispatcher # Program options device = "/dev/ttyACM0" log = "None" sniff = 300.0 # manager options options = ZWaveOption(device, \ user_path="/home/pi/Embedded_OS/final/zwave_cfg/", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level(log) options.set_logging(True) options.lock() # fill below with more useful things later def louie_network_started(network): print( "Hello from network : I'm started : homeid {:08x} - {} nodes were found." .format(network.home_id, network.nodes_count)) def louie_network_failed(network): print("Hello from network : can't load :(.")
class ZWaveCommander: def __init__(self, stdscr): self._curAlert = False self._alertStack = list() self._driverInitialized = False self._options = None self._network = None self._listMode = True self._screen = stdscr self._version = '0.1 Beta 1' self._listtop = 0 self._listindex = 0 self._listcount = 0 self._selectedNode = None self._stop = threading.Event() self._keys = { 'A' : 'Add', 'B' : 'About', 'D' : 'Delete', 'R' : 'Refresh', 'S' : 'Setup', '+' : 'Increase', '-' : 'Decrease', '1' : 'On', '0' : 'Off', 'Q' : 'Quit' } #self._network = ZWaveWrapper.getInstance(device=self._config['device'], config=self._config['config'], log=None) self._options = ZWaveOption( \ device="/dev/zwave-aeon-s2", \ config_path="openzwave/config", \ user_path=".", \ cmd_line="") self._options.set_log_file("OZW_Log.log") self._options.set_append_log_file(False) self._options.set_save_log_level('Debug') self._options.set_console_output(False) self._options.set_logging(True) self._options.lock() # TODO: add log level to config # TODO: add log enable/disable to config # TODO: logging - can ozw log be redirected to file? If so, we can add ability to view/tail log FORMAT='%(asctime)s\t%(levelname)s\t%(name)s\t%(message)s' logging.basicConfig(filename='zwaveCommander.log', level=logging.DEBUG, format=FORMAT) self._log = logging.getLogger('ZWaveCommander') self._logbar ='\n%s\n' % ('-'*60) def main(self): '''Main run loop''' self._log.info('%sZWaveCommander Version %s Starting%s', self._logbar, self._version, self._logbar) self._initCurses(self._screen) try: self._startNetwork() self._runLoop() finally: self._shutdown() def _delayloop(self, context, duration, callback): self._log.debug('thread %s sleeping...', context) time.sleep(duration) self._log.debug('timer %s expired, executing callback %s', context, callback) if context == 'alert': self._curAlert = False if self._alertStack: self._alert(self._alertStack.pop()) if callback is not None: callback() def _handleQuit(self): # TODO: exit confirmation dialog self._log.info('Stop requested') self._stop.set() def _handleRefresh(self): if self._selectedNode: self._network.refresh(self._selectedNode) def _handleOn(self): if self._selectedNode: self._network.setNodeOn(self._selectedNode) def _handleOff(self): if self._selectedNode: self._network.setNodeOff(self._selectedNode) def _handleIncrease(self): if self._selectedNode: curLevel = self._selectedNode.level newLevel = curLevel + 10 if newLevel > 99: newLevel = 99 self._network.setNodeLevel(self._selectedNode, newLevel) def _handleDecrease(self): if self._selectedNode: curLevel = self._selectedNode.level newLevel = curLevel - 10 if newLevel < 0: newLevel = 0 self._network.setNodeLevel(self._selectedNode, newLevel) def _setTimer(self, context, duration, callback): newTimer = threading.Thread(None, self._delayloop, 'cb-thread-%s' % context, (context, duration, callback), {}) newTimer.setDaemon(True) newTimer.start() def _alert(self, text): '''perform program alert''' if not self._curAlert: self._curAlert = True curses.flash() self._screen.addstr(self._screensize[0] - 1, 0, ' {0:{width}}'.format(text, width=self._screensize[1] - 2), curses.color_pair(self.COLOR_ERROR)) self._screen.refresh() self._setTimer('alert', 1, self._redrawMenu) else: self._alertStack.append(text) def _layoutScreen(self): # TODO: handle screen resize on curses.KEY_RESIZE in loop (tear down, re-calculate, and re-build) # top 5 lines (fixed): system info (including list header) # bottom line (fixed): menu/status # remaining top half: item list (scrolling) # remaining bottom half: split - left half=static info, right half=detail (scrolling) # item list: 8 columns. All column widths here are padded with 1 char space (except col 0, which is always 1 char) # c0=1 char fixed (select indicator) # c1=4 char fixed (id) # c2=10 char min (name) # c3=10 char min (location) # c4=20 char min (type) # c5=9 char fixed (state) # c6=7 char fixed (batt) # c7=7 char fixed (signal) # last three columns: 23 chars: are optional and can fall off if space requires it (min width 45) # "min" columns expand evenly to fit remaining space self._screen.clear() self._log.debug("Laying out screen") self._colwidths=[1,4,10,10,15,12,8,8] self._colheaders=['','ID','Name','Location','Type','State','Batt','Signal'] self._detailheaders=['Info','Values','Classes','Groups','Events'] self._flexcols=[2,3,4] self._rowheights=[5,5,10,1] self._flexrows=[1,2] self._deviceValueColumns=['id','commandClass','instance','index','type','label','value','units'] self._deviceValueWidths= [10,20,9,6,10,20,10,10] self._sortcolumn = self._colheaders[1] self._detailview = self._detailheaders[0] self._screensize = self._screen.getmaxyx() width = self._screensize[1] height = self._screensize[0] self._log.debug('Screen is %d wide by %d high', width, height) # Update dynamic column widths for device list self._log.debug('Initial column widths are: %s', self._colwidths) cwid = 0 for i in self._colwidths: cwid += i flexwidth = width - cwid if flexwidth > 0: adder = divmod(flexwidth, len(self._flexcols)) for i in self._flexcols: self._colwidths[i] += adder[0] self._colwidths[self._flexcols[-1]] += adder[1] self._log.debug('Adjusted column widths are: %s' ,self._colwidths) # Update dynamic row heights for screen sections self._log.debug('Initial row heights are: %s' , self._rowheights) cht = 0 for i in self._rowheights: cht += i flexheight = height - cht if flexheight > 0: adder = divmod(flexheight, len(self._flexrows)) for i in self._flexrows: self._rowheights[i] += adder[0] self._rowheights[self._flexrows[-1]] += adder[1] self._log.debug('Adjusted row heights are: %s' , self._rowheights) if curses.has_colors(): self._log.debug('Curses initialized: %d colors and %d color pairs available', curses.COLORS, curses.COLOR_PAIRS) else: self._log.debug('Curses initialized, but no colors are available') self._listpad = curses.newpad(256,256) self._detailpads = { 'Info': curses.newpad(self._rowheights[2], self._screensize[1]), 'Values': curses.newpad(128, self._screensize[1]), 'Classes': curses.newpad(128, self._screensize[1]), 'Groups': curses.newpad(self._rowheights[2], self._screensize[1]), 'Events': curses.newpad(256, self._screensize[1]) } self._detailpos = dict() for k in self._detailpads.iterkeys(): self._detailpos[k] = 0 self._detailtop = self._rowheights[0] + self._rowheights[1] + 2 self._detailbottom = self._detailtop + self._rowheights[2] - 3 self._updateColumnHeaders() def _initCurses(self, stdscr): '''Configure ncurses application-specific environment (ncurses has already been initialized)''' curses.curs_set(0) # Re-define color attributes... self.COLOR_NORMAL=1 self.COLOR_HEADER_NORMAL=2 self.COLOR_HEADER_HI=3 self.COLOR_ERROR=4 self.COLOR_CRITICAL=5 self.COLOR_WARN=6 self.COLOR_OK=7 curses.init_pair(self.COLOR_NORMAL, curses.COLOR_WHITE, curses.COLOR_BLACK) # normal (selected row is inverted, disabled/sleep is dim) curses.init_pair(self.COLOR_HEADER_NORMAL, curses.COLOR_BLACK, curses.COLOR_GREEN) # header normal curses.init_pair(self.COLOR_HEADER_HI, curses.COLOR_WHITE, curses.COLOR_CYAN) # header hi curses.init_pair(self.COLOR_ERROR, curses.COLOR_YELLOW, curses.COLOR_RED) # error text curses.init_pair(self.COLOR_CRITICAL, curses.COLOR_RED, curses.COLOR_BLACK) # critical curses.init_pair(self.COLOR_WARN, curses.COLOR_YELLOW, curses.COLOR_BLACK) # warn curses.init_pair(self.COLOR_OK, curses.COLOR_GREEN, curses.COLOR_BLACK) # ok self._layoutScreen() def _handleSetup(self): self._alert('handleSetup not yet implemented') def _checkIfInitialized(self): if not self._driverInitialized: msg = 'Unable to initialize driver - check configuration' self._alert(msg) self._log.warning(msg) self._handleSetup() else: self._log.info('OpenZWave initialized successfully.') def _notifyDriverReady(self, network, controller): self._log.info('OpenZWave Driver is Ready; homeid is %0.8x. %d nodes were found.' % (network.home_id, network.nodes_count)) self._driverInitialized = True self._addDialogText(2,'Driver initialized with homeid %0.8x' % network.home_id) self._addDialogText(3,'Node Count is now %' % network.nodes_count) def _notifyNodeAdded(self, network, node): self._addDialogText(3,'Node Count is now %s'.format(network.nodes_count)) self._updateSystemInfo() def _redrawAll(self): self._clearDialog() self._updateSystemInfo() self._updateDeviceList() self._updateColumnHeaders() self._updateDeviceDetail() def _notifyNetworkReady(self, network, controller): self._log.info('OpenZWave Initialization Complete.') self._alert('OpenZWave Initialization Complete.') self._redrawAll() def _notifyNetworkFailed(self, network): self._log.info('OpenZWave Initialization failed.') self._alert('OpenZWave Initialization failed.') self._redrawAll() def _notifyNodeReady(self, network, node): self._readyNodeCount += 1 self._addDialogText(2, 'OpenZWave is querying associated devices') self._addDialogText(3,'Node %s is now ready' % node.node_id) self._addDialogProgress(5, self._readyNodeCount, network.nodes_count) self._updateDeviceList() def _notifyValueChanged(self, signal, **kw): nodeId = kw['nodeId'] self._log.debug('Got value changed notification for node {0}'.format(nodeId)) # TODO: this is very heavy handed - just update appropriate elements self._updateDeviceList() self._updateDeviceDetail() def _initDialog(self, height, width, buttons=('OK',), caption=None): self._dialogpad = curses.newpad(height, width) self._dialogpad.bkgd(0x94, curses.color_pair(self.COLOR_HEADER_HI)) self._dialogpad.clear() self._dialogpad.box() if caption: lh = (width / 2) - (len(caption) / 2) - 1 self._dialogpad.addstr(0, lh, ' {0} '.format(caption), curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT) if buttons: if len(buttons) > 1: bwid = 0 for bcap in buttons: if len(bcap) > bwid: bwid = len(bcap) cellwid = (width - 4) / len(buttons) lpad = (cellwid - bwid) / 2 - 1 rpad = cellwid - bwid - lpad - 1 self._dialogpad.move(height - 2, 1) else: bwid = len(buttons[0]) lpad = rpad = 1 self._dialogpad.move(height - 2, (width / 2) - (bwid / 2) - 2) for button in buttons: self._dialogpad.addstr('{0:{wlpad}}<{1:^{wbwid}}>{0:{wrpad}}'.format('',button, wlpad=lpad, wbwid=bwid, wrpad=rpad)) dt = (self._screensize[0] / 2) - (height / 2) dl = (self._screensize[1] / 2) - (width / 2) dc = padcoords(sminrow=dt,smincol=dl,smaxrow=dt+height - 1, smaxcol=dl+width - 1) self._dialogcoords = dc self._dialogpad.overlay(self._screen, 0, 0, dc.sminrow, dc.smincol, dc.smaxrow, dc.smaxcol) self._screen.refresh() def _clearDialog(self): del self._dialogpad self._dialogpad = None self._dialogcoords = None self._screen.touchwin() self._screen.refresh() def _updateDialog(self): if self._dialogpad: self._screen.refresh() dc = self._dialogcoords self._dialogpad.refresh(0,0,dc.sminrow, dc.smincol, dc.smaxrow, dc.smaxcol) def _addDialogText(self, row, text, align='^'): if self._dialogpad: self._dialogpad.addstr(row, 1, '{0:{aln}{wid}}'.format(text, aln=align, wid=self._dialogpad.getmaxyx()[1] - 2)) self._updateDialog() def _addDialogProgress(self, row, current, total, showPercent=True, width=None): if self._dialogpad: dc = self._dialogcoords if width is None: width = (dc.smaxcol - dc.smincol) * 2 / 3 pct = float(current) / float(total) filled = int(pct * float(width)) lh = ((dc.smaxcol - dc.smincol) / 2) - (width / 2) self._dialogpad.addch(row, lh - 1, '[', curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._dialogpad.addch(row, lh + width, ']', curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._dialogpad.addstr(row, lh, ' '*width, curses.color_pair(self.COLOR_NORMAL)) self._dialogpad.addstr(row, lh, '|'*filled, curses.color_pair(self.COLOR_OK) | curses.A_BOLD) if showPercent: pctstr = '{0:4.0%}'.format(pct) lh = ((dc.smaxcol - dc.smincol) / 2) - (len(pctstr) / 2) self._dialogpad.addstr(row, lh, pctstr, curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._updateDialog() def _startNetwork(self): dispatcher.connect(self._notifyDriverReady, ZWaveNetwork.SIGNAL_DRIVER_READY) dispatcher.connect(self._notifyNetworkReady, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self._notifyNetworkFailed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self._notifyNodeReady, ZWaveNetwork.SIGNAL_NODE_READY) dispatcher.connect(self._notifyValueChanged, ZWaveNetwork.SIGNAL_VALUE_CHANGED) dispatcher.connect(self._notifyNodeAdded, ZWaveNetwork.SIGNAL_NODE_ADDED) self._initDialog(10,60,['Cancel'],'Progress') self._addDialogText(2,'Initializing OpenZWave') self._log.info('Initializing OpenZWave') self._network = ZWaveNetwork(self._options, log=self._log) #self._network = ZWaveWrapper.getInstance(device=self._config['device'], config=self._config['config'], log=None) self._setTimer('initCheck', 3, self._checkIfInitialized) while not self._stop.isSet() and not self._driverInitialized: time.sleep(0.1) # TODO: handle keys here... cancel/etc def _runLoop(self): while not self._stop.isSet(): key = self._screen.getch() if key == curses.KEY_DOWN: self._switchItem(1) elif key == curses.KEY_UP: self._switchItem(-1) elif key == curses.KEY_LEFT: self._switchTab(-1) elif key == curses.KEY_RIGHT: self._switchTab(1) elif key == 0x09: self._nextMode() elif key is not None: self._handleMnemonic(key) def _handleMnemonic(self, key): for mnemonic, func in self._keys.iteritems(): if key == ord(mnemonic[0].lower()) or key == ord(mnemonic[0].upper()): funcname = '_handle%s' % func try: method = getattr(self, funcname) method() except AttributeError as ex: msg = 'No method named [%s] defined!' % funcname self._log.warn('handleMnemonic: %s', msg) self._log.warn('handleMnemonic Exception Details: %s', str(ex)) self._alert(msg) break def _resetDetailPos(self): for p in self._detailpos.iterkeys(): self._detailpos[p] = 0 def _switchItem(self, delta): if self._listMode: n = self._listindex + delta if n in range(0, self._listcount): self._listindex = n self._updateDeviceList() # TODO: we don't really need to redraw everything when selection changes self._resetDetailPos() self._updateDeviceDetail() else: self._detailpos[self._detailview] += delta self._updateDeviceDetail() def _switchTab(self, delta): if self._listMode: i = self._colheaders.index(self._sortcolumn) i += delta if i > len(self._colheaders) - 1: i = 1 elif i < 1: i = len(self._colheaders) - 1 self._sortcolumn = self._colheaders[i] else: i = self._detailheaders.index(self._detailview) i += delta if i > len(self._detailheaders) - 1: i = 0 elif i < 0: i = len(self._detailheaders) - 1 self._detailview = self._detailheaders[i] self._updateColumnHeaders() self._updateDeviceList() self._updateDeviceDetail() def _nextMode(self): self._listMode = not self._listMode self._updateColumnHeaders() def _shutdown(self): # TODO: handle orderly shutdown pass def _rightPrint(self, row, data, attrs=None): if attrs is None: attrs = curses.color_pair(self.COLOR_NORMAL) self._screen.addstr(row, self._screensize[1] - len(data), data, attrs) def _updateSystemInfo(self): self._screen.addstr(0,1,'%s on %s' % \ (self._network.controller.description, self._network.controller.device), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.addstr(1,1,'Home ID 0x%0.8x' % \ (self._network.self._network.home_id), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.move(2,1) self._screen.addstr('%s Registered Nodes' % \ (self._network.nodes_count), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.addstr(' (%s Sleeping)' % \ (self._network.sleeping_nodes_count), \ curses.color_pair(self.COLOR_NORMAL) | curses.A_DIM) self._rightPrint(0, 'Library' % \ (self._network.controller.library_description)) self._rightPrint(1, 'Python Library Version %s' % \ (self._network.controller.python_library_version)) self._screen.refresh() def _updateColumnHeaders(self): self._screen.move(4,0) for text, wid in zip(self._colheaders, self._colwidths): clr = curses.color_pair(self.COLOR_HEADER_NORMAL) if self._listMode else curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT if text == self._sortcolumn: clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD self._screen.addstr('{0:<{width}}'.format(text, width=wid), clr) self._screen.move(self._rowheights[0] + self._rowheights[1] + 1, 0) clr = curses.color_pair(self.COLOR_HEADER_NORMAL) if not self._listMode else curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT self._screen.addstr('{0:{width}}'.format('', width=self._screensize[1]), clr) self._screen.move(self._rowheights[0] + self._rowheights[1] + 1, 0) for text in self._detailheaders: clr = curses.color_pair(self.COLOR_HEADER_NORMAL) if not self._listMode else curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT if text == self._detailview: clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD wid = len(text) self._screen.addstr(' {0:<{width}} '.format(text, width=wid), clr) def _fixColumn(self, text, width, align='<'): retval = '{0:{aln}{wid}}'.format(text, aln=align, wid=width) if len(retval) > width: retval = retval[:width] return retval def _getListItemColor(self, drawSelected): return curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT if drawSelected \ else curses.color_pair(self.COLOR_NORMAL) def _drawMiniBar(self, value, minValue, maxValue, drawWidth, drawSelected, drawPercent=False, colorLevels=None): clr = self._getListItemColor(drawSelected) pct = float(value) / float(maxValue) dw = drawWidth - 2 filled = int(pct * float(dw)) fillcolor = clr if not drawSelected: fillcolor = curses.color_pair(self.COLOR_OK) if colorLevels: if pct <= colorLevels.error: fillcolor = curses.color_pair(self.COLOR_CRITICAL) elif pct <= colorLevels.warning: fillcolor = curses.color_pair(self.COLOR_WARN) self._listpad.addch('[', clr | curses.A_BOLD) self._listpad.addstr('|' * filled, fillcolor) self._listpad.addstr(' ' * (dw - filled), clr) self._listpad.addch(']', clr | curses.A_BOLD) # TODO: draw percent text if requested def _drawNodeStatus(self, node, drawSelected): clr = self._getListItemColor(drawSelected) if node.is_sleeping: self._listpad.addstr(self._fixColumn('(sleeping)', self._colwidths[5]), clr | curses.A_LOW) elif node.has_command_class(0x76): # lock self._listpad.addstr(self._fixColumn('Locked' if node.is_locked else 'Unlocked', self._colwidths[5]), clr) elif node.has_command_class(0x26): # multi-level switch self._drawMiniBar(node.level, 0, 99, self._colwidths[5], drawSelected) elif node.has_command_class(0x25): # binary switch self._listpad.addstr(self._fixColumn('ON' if node.is_on else 'OFF', self._colwidths[5]), clr) else: self._listpad.addstr(self._fixColumn('OK', self._colwidths[5]), clr) def _drawBatteryStatus(self, node, drawSelected): clr = self._getListItemColor(drawSelected) if node.has_command_class(0x80): self._drawMiniBar(node.batteryLevel, 0, 100, self._colwidths[6], drawSelected, colorLevels=colorlevels(error=0.10,warning=0.40)) else: self._listpad.addstr(self._fixColumn('', self._colwidths[6]), clr) def _drawSignalStrength(self, node, drawSelected): clr = self._getListItemColor(drawSelected) self._listpad.addstr(self._fixColumn('', self._colwidths[7]), clr) def _drawDeviceNodeLine(self, node, drawSelected): clr = self._getListItemColor(drawSelected) self._listpad.addstr(' ', clr) self._listpad.addstr(self._fixColumn(node.id, self._colwidths[1]), clr) self._listpad.addstr(self._fixColumn(node.name, self._colwidths[2]), clr) self._listpad.addstr(self._fixColumn(node.location, self._colwidths[3]), clr) self._listpad.addstr(self._fixColumn(node.productType, self._colwidths[4]), clr) self._drawNodeStatus(node, drawSelected) self._drawBatteryStatus(node, drawSelected) self._drawSignalStrength(node, drawSelected) def _updateDeviceList(self): self._listcount = self._network.nodes_count idx = 0 for node in self._network._nodes.itervalues(): if idx == self._listindex: self._selectedNode = node self._listpad.move(idx,0) self._drawDeviceNodeLine(node, idx == self._listindex) idx += 1 ctop = self._rowheights[0] listheight = self._rowheights[1] if self._listindex - self._listtop > listheight: self._listtop = self._listindex - listheight elif self._listindex < self._listtop: self._listtop = self._listindex self._screen.refresh() self._listpad.refresh(self._listtop, 0, ctop, 0, ctop + listheight, self._screensize[1] - 1) self._updateDialog() def _redrawDetailTab(self, pad): self._screen.refresh() pad.refresh(0, 0, self._detailtop, 0, self._detailbottom, self._screensize[1] - 1) def _updateDetail_Values(self, pad): # Draw column header clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD pad.addstr(0,0,'{0:<{width}}'.format(' ', width=self._screensize[1]), clr) pad.move(0,1) for text, wid in zip(self._deviceValueColumns, self._deviceValueWidths): pad.addstr('{0:<{width}}'.format(text.title(), width=wid), clr) node = self._selectedNode if node and node.values: # Grab all items except for configuration values (they have their own tab) vset = list() for value in node.values.itervalues(): if value.valueData: vset.append(value) # Sort the resulting set: (1) command class, (2) instance, (3) index s = sorted(sorted(sorted(vset, key=lambda value: value.getValue('index')), key=lambda value: value.getValue('instance')), key=lambda value: value.getValue('commandClass')) if self._detailpos[self._detailview] >= len(s): self._detailpos[self._detailview]=len(s)-1 i = 0 for value in s: vdic = value.valueData pad.move(i+1,0) # TODO: reset detail position on parent item change drawSelected = self._detailpos['Values'] == i clr = self._getListItemColor(drawSelected) pad.addstr(' ' * self._screensize[1], clr) pad.move(i+1,1) i += 1 for key, wid in zip(self._deviceValueColumns, self._deviceValueWidths): clr = self._getListItemColor(drawSelected) text = value.getValue(key) # strip 'COMMAND_CLASS_' prefix to save some space if key == 'commandClass' and text.startswith('COMMAND_CLASS_'): text = text[14:] # TODO: value decorators (checkbox for Booleans, edit box for others) # decimal: format to 2 places # bool as checkbox # byte as minibar if editable # ints need to be directly edited... # buttons... ? # Draw editable items differently if key == 'value' and not vdic['readOnly'] and drawSelected: clr = curses.color_pair(self.COLOR_ERROR) pad.addstr(self._fixColumn(text, wid), clr) def _updateDetail_Info(self, pad): node = self._selectedNode if node: #baudRate, basic, generic, specific, version, security self._deviceInfoColumns=['id','name','location','capabilities','neighbors','manufacturer','product','productType'] if self._detailpos[self._detailview] >= len(self._deviceInfoColumns): self._detailpos[self._detailview]=len(self._deviceInfoColumns)-1 editableColumns=['name','location','manufacturer','product'] i = maxwid = 0 for name in self._deviceInfoColumns: maxwid = len(name) if len(name) > maxwid else maxwid colwidth = maxwid + 2 clr = self._getListItemColor(False) clr_rw = curses.color_pair(self.COLOR_ERROR) clr_ro = self._getListItemColor(True) clr_col = curses.color_pair(self.COLOR_OK) # TODO: If editable, should be textpad for column in self._deviceInfoColumns: val = str(getattr(node, column)) pad.move(i + 1, 1) pad.addstr('{0:>{width}}'.format(column.title() + ':', width=colwidth), clr_col) selected = i == self._detailpos[self._detailview] thisclr = clr if selected: thisclr = clr_rw if column in editableColumns else clr_ro i += 1 pad.addstr(' ') pad.addstr('{0:<{width}}'.format(val, width=30), thisclr) def _updateDetail_Classes(self, pad): clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD pad.addstr(0,0,'{0:<{width}}'.format(' CommandClass', width=self._screensize[1]), clr) node = self._selectedNode if node: if self._detailpos[self._detailview] >= len(node.commandClasses): self._detailpos[self._detailview]=len(node.commandClasses)-1 i = 0 for cc in node.commandClasses: pad.addstr(i + 1, 0, ' {0:<{width}}'.format(self._network.getCommandClassName(cc), width=30), self._getListItemColor(i == self._detailpos[self._detailview])) i += 1 def _updateDetail_Groups(self, pad): pad.addstr(3,3,'Group view not yet implemented') # groups tab: # index label maxMembers members # 1 my group 4 1, 2, 4 # Members column is editable - enter comma-separated list? def _updateDetail_Events(self, pad): pad.addstr(3,3,'Event view not yet implemented') # event detail tab: # timestamp commandClass notificationType def _updateDeviceDetail(self): # TODO: detail needs to be scrollable, but to accomplish that a couple of changes need to be made. First, the detail header band needs to be moved into a static shared section (above the detail pad); second, a new dict of 'top' positions needs to be created; finally, positioning code needs to be written to correctly offset the pad. pad = self._detailpads[self._detailview] pad.clear() if self._detailpos[self._detailview] < 0: self._detailpos[self._detailview]=0 funcname = '_updateDetail_{0}'.format(self._detailview) try: method = getattr(self, funcname) method(pad) except AttributeError as ex: msg = 'No method named [%s] defined!' % funcname self._log.warn('_updateDeviceDetail: %s', msg) self._log.warn('_updateDeviceDetail Exception Details: %s', str(ex)) self._alert(msg) self._redrawDetailTab(pad) def _updateMenu(self): menurow = self._screensize[0] - 1 self._screen.addstr(menurow, 0, ' ' * (self._screensize[1] - 1), curses.color_pair(self.COLOR_HEADER_NORMAL)) self._screen.move(menurow,4) for mnemonic, text in self._keys.iteritems(): self._screen.addstr(' {0} '.format(mnemonic), curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._screen.addstr('{0}'.format(text), curses.color_pair(self.COLOR_HEADER_NORMAL)) def _redrawMenu(self): self._updateMenu() self._screen.refresh()
elif arg.startswith("--sniff"): temp, sniff = arg.split("=") sniff = float(sniff) elif arg.startswith("--help"): print("help : ") print(" --device=/dev/yourdevice ") print(" --log=Info|Debug") #Define some manager options options = ZWaveOption(device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level("Debug") #options.set_save_log_level('Info') options.set_logging(True) options.lock() def louie_network_started(network): print('//////////// ZWave network is started ////////////') print('Louie signal : OpenZWave network is started : homeid %0.8x - %d nodes were found.' % \ (network.home_id, network.nodes_count)) def louie_network_resetted(network): print('Louie signal : OpenZWave network is resetted.')
#from openzwave.node import ZWaveNode #from openzwave.value import ZWaveValue #from openzwave.scene import ZWaveScene #from openzwave.controller import ZWaveController device = "/dev/ttyACM0" sniff = 300.0 options = ZWaveOption(device, config_path="./ozw/config", user_path="./zwave/", cmd_line="") options.set_log_file("./zwave/OZW_Log.log") options.set_append_log_file(True) options.set_console_output(True) options.set_save_log_level("Warning") #options.set_save_log_level("Debug") options.set_logging(True) options.lock() network = ZWaveNetwork(options, autostart=False) def make_printer(prefix): def f(*a, **kw): try: things = [] if "network" in kw: kw.pop("network") if "signal" in kw: assert kw.pop("signal") == prefix
class MyZwave: device="/dev/ttyACM0" config_path="/home/pi/Documents/Development/Python/python-openzwave-0.3.2/openzwave/config" log="Debug" network = None options = None def __init__(self): self.device="/dev/ttyACM0" self.config_path="/home/pi/Documents/Development/Python/python-openzwave-0.3.2/openzwave/config" self.log="Debug" self.network = None self.options = None def initZwave(self): self.options = ZWaveOption(self.device, config_path=self.config_path, user_path=".", cmd_line="") self.options.set_log_file("MyZWave_log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) #self.options.set_console_output(True) self.options.set_save_log_level(self.log) self.options.set_logging(False) self.options.lock() self.network = ZWaveNetwork(self.options, log=None) time_started=0 print("*** Waiting for network to awake: ") for i in range(0,300): if self.network.state >= self.network.STATE_AWAKED: print(" done") break else: sys.stdout.write(".") sys.stdout.flush() time_started += 1 time.sleep(1.0) if self.network.state < self.network.STATE_AWAKED: print(".") print("Network is not awaked") for i in range(0,300): if self.network.state >= self.network.STATE_READY: print(" done in{} seconds".format(time_started)) break else: sys.stdout.write(".") sys.stdout.flush() time_started += 1 time.sleep(1.0) if not self.network.is_ready: print(".") print("Network is not ready") def toggleSwitch(self,nodeNum): node=self.network.nodes[nodeNum] print("Node: {}".format(node)) val=node.get_switches().keys()[0] print("Values: {}".format(val)) state = node.get_switch_state(val) print("State: {}".format(state)) node.set_switch(val,not state) time.sleep(0.2) state = node.get_switch_state(val) return "on" if state else "off" def getSwitchStatus(self, nodeNum): node = self.network.nodes[nodeNum] val = node.get_switches().keys()[0] state = node.get_switch_state(val) return "on" if state else "off" def getInt(self, strNo): if strNo == None: return 0 else: try: temp = int(strNo) except ValueError: temp = 0 return temp
class MainWindow(Screen): def __init__(self, device=None, footer=False, name=None): Screen.__init__(self) self.device = device self.footer_display = footer self._define_log() self._define_screen() self._connect_louie() self._start_network() def _define_log(self): hdlr = logging.FileHandler('/tmp/urwidcmd.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) self.log = logging.getLogger('openzwave') self.log.addHandler(hdlr) self.log.setLevel(logging.DEBUG) self.log.info("="*15 + " start " + "="*15) def _define_screen(self): self._palette = [("title", "yellow", "dark cyan"), ("keys", "dark blue", "light gray"), ("message", "light cyan", "dark green"), ("linenr", "light blue", "dark cyan"), ("input", "light gray", "black"), ("input2", "dark red", "light gray"), ("focus", "black", "light gray", "bold"), ("dialog", "black", "light gray", "bold"), ("file", "light green", "dark blue"), ("errortxt", "dark red", "dark blue"), ("selectedfile", "yellow", "dark blue"), ("selectedfocus", "yellow", "light gray", "bold"), ("dir", "light gray", "dark blue"), ("fileedit", "light green", "dark red"), ('edit', 'yellow', 'dark blue'), ('body','default', 'default'), ('foot','dark cyan', 'dark blue', 'bold'), ('shadow','white','black'), ('border','black','dark blue'), ('error','black','dark red'), ('FxKey','light cyan', 'dark blue', 'underline')] self.network = None self.controller = None self.root_box = RootBox(self, None, "body") self.stat_box = StatBox(self, self.root_box, "body") self.controller_box = ControllerBox(self, self.root_box, "body") self.scenes_box = ScenesBox(self, self.root_box, "body") self.scene_box = SceneBox(self, self.scenes_box, "body") self.nodes_box = NodesBox(self, self.root_box, "body") self.switches_box = SwitchesBox(self, self.nodes_box, "body") self.dimmers_box = DimmersBox(self, self.nodes_box, "body") self.sensors_box = SensorsBox(self, self.nodes_box, "body") self.node_box = NodeBox(self, self.nodes_box, "body") self.values_box = ValuesBox(self, self.node_box, "body") self.groups_box = GroupsBox(self, self.node_box, "body") self.status_bar = StatusBar(self) self.header_bar = HeaderBar(self) self.framefocus = 'footer' self._active_box = self.root_box self.frame = urwid.Frame(urwid.AttrWrap(self.active_box, 'body'), \ header=self.header_bar,\ footer=self.status_bar, \ focus_part=self.framefocus) self.active_box = self.root_box self.loop = urwid.MainLoop(self.frame, \ self._palette, \ unhandled_input=self._unhandled_input) @property def active_box(self): """ Gets the number of association groups reported by this node. :rtype: int """ return self._active_box @active_box.setter def active_box(self,value): """ Gets the number of association groups reported by this node. :rtype: int """ self._active_box = value self.frame.set_body(self._active_box) self.header_bar.update(self._active_box.walker.fullpath()) def exit(self): """ Quit the programm Clean network properly and exit """ self.network.write_config() self.network.stop() raise urwid.ExitMainLoop() def execute(self, command): """ Parse an execute a commande """ command = command.strip() if command.startswith('ls') : if ' ' in command : cmd,options = command.split(' ') else: options = "" options = options.strip() self.active_box.walker.ls(options) self.status_bar.set_command("") return True elif command.startswith('exit') : self.exit() elif command.startswith('cd') : if ' ' in command : cmd,path = command.split(' ',1) else: path = "/" path = path.strip() if self.active_box.walker.exist(path): self.active_box = self.active_box.walker.cd(path) self.active_box.walker.ls("") self.status_bar.set_command("") self.log.info(" self.active_box %s" % self.active_box.walker.path) return True elif path == "/" : self.active_box = self.root_box self.active_box.walker.ls("") self.status_bar.set_command("") self.log.info(" self.active_box %s" % self.active_box.walker.path) return True else: self.status_bar.update(status='Unknown directory "%s"' % path) return False elif command.startswith('send') : if ' ' in command : cmd,value = command.split(' ',1) else: self.status_bar.update(status='Usage : send <command>') return False value = value.strip() if len(value) == 0 : self.status_bar.update(status='Usage : send <command>') return False if self.active_box.walker.send(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False elif command.startswith('create') : if ' ' in command : cmd,value = command.split(' ',1) else: self.status_bar.update(status='Usage : create <value>') return False value = value.strip() if len(value) == 0 : self.status_bar.update(status='Usage : create <value>') return False if self.active_box.walker.create(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False elif command.startswith('delete') : if ' ' in command : cmd,value = command.split(' ',1) else: self.status_bar.update(status='Usage : delete <value>') return False value = value.strip() if len(value) == 0 : self.status_bar.update(status='Usage : delete <value>') return False if self.active_box.walker.delete(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False elif command.startswith('activate') : if ' ' in command : cmd,value = command.split(' ',1) else: self.status_bar.update(status='Usage : activate <value>') return False value = value.strip() if len(value) == 0 : self.status_bar.update(status='Usage : activate <value>') return False if self.active_box.walker.activate(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False elif command.startswith('set') : if ' ' in command : cmd,end = command.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : set <field> to <value>') return False end = end.strip() field,end = end.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : set <field> to <value>') return False end = end.strip() to,value = end.split(' ',1) if len(value) == 0 or to != "to" : self.status_bar.update(status='Usage : set <field> to <value>') return False value = value.strip() if self.active_box.walker.set(field, value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False else : self.status_bar.update(status='Usage : set <field> to <value>') return False elif command.startswith('poll') : if ' ' in command : cmd,end = command.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : poll <value> to <intensity>') return False end = end.strip() field,end = end.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : poll <value> to <intensity>') return False end = end.strip() to,value = end.split(' ',1) if len(value) == 0 or to != "to" : self.status_bar.update(status='Usage : poll <value> to <intensity>') return False value = value.strip() if self.active_box.walker.poll(field, value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False else : self.status_bar.update(status='Usage : poll <value> to <intensity>') return False elif command.startswith('add') : if ' ' in command : cmd,end = command.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : add <value> to <list>') return False end = end.strip() field,end = end.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : add <value> to <list>') return False end = end.strip() to,value = end.split(' ',1) if len(value) == 0 or to != "to" : self.status_bar.update(status='Usage : add <value> to <list>') return False value = value.strip() if self.active_box.walker.add(value, field): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False else : self.status_bar.update(status='Usage : add <value> to <list>') return False elif command.startswith('remove') : if ' ' in command : cmd,end = command.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : remove <value> from <list>') return False end = end.strip() field,end = end.split(' ',1) if len(end) == 0 or ' ' not in end : self.status_bar.update(status='Usage : remove <value> from <list>') return False end = end.strip() to,value = end.split(' ',1) if len(value) == 0 or to != "from" : self.status_bar.update(status='Usage : remove <value> from <list>') return False value = value.strip() if self.active_box.walker.remove(value, field): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : return False else : self.status_bar.update(status='Usage : remove <value> from <list>') return False elif command.startswith('reset') : if ' ' in command : cmd,state = command.split(' ',1) state = state.strip() if len(state) == 0 : self.status_bar.update(status='Usage : reset soft|hard') return False if self.active_box.walker.reset(state): self.active_box.walker.ls("") self.status_bar.set_command("") return True else : self.status_bar.update(status='Unknowm state "%s"' % state) return False else: self.status_bar.update(status='Unknown command "%s"' % command) return False def _unhandled_input(self, key): if key == 'esc': self.exit() elif key == 'tab' or key == 'shift tab': if self.framefocus == 'footer': self.framefocus = 'body' else: self.framefocus = 'footer' self.frame.set_focus(self.framefocus) return True elif key == 'enter': self.log.info('handled: %s' % repr(key)) cmd = self.status_bar.get_command() self.execute(cmd) return True elif key == 'f5': self.refresh_nodes() return True else: self.log.info('unhandled: %s' % repr(key)) def _start_network(self): #Define some manager options self.options = ZWaveOption(self.device, \ config_path="openzwave/config", \ user_path=".", cmd_line="") self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level("Internal") self.options.set_logging(True) self.options.lock() self.network = ZWaveNetwork(self.options, self.log) self.status_bar.update(status='Start Network') def _connect_louie(self): dispatcher.connect(self._louie_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._louie_network_resetted, ZWaveNetwork.SIGNAL_NETWORK_RESETTED) dispatcher.connect(self._louie_network_awaked, ZWaveNetwork.SIGNAL_NETWORK_AWAKED) dispatcher.connect(self._louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self._louie_network_stopped, ZWaveNetwork.SIGNAL_NETWORK_STOPPED) def _louie_network_started(self, network): self.log.info('OpenZWave network is started : homeid %0.8x - %d nodes were found.' % \ (network.home_id, network.nodes_count)) self.network = network self.status_bar.update(status='OpenZWave network is started ... Waiting ...') self.loop.draw_screen() def _louie_network_resetted(self, network): self.log.info('OpenZWave network is resetted.') self.network = None #self._disconnect_louie_node_and_value() self.status_bar.update(status='OpenZWave network was resetted ... Waiting ...') self.loop.draw_screen() def _louie_network_stopped(self, network): self.log.info('OpenZWave network is stopped.') self.network = None self.status_bar.update(status='OpenZWave network was stopped ... please quit') self.loop.draw_screen() def _louie_network_awaked(self, network): self.log.info('OpenZWave network is awaked.') self.network = network self.status_bar.update(status='OpenZWave network is awaked ... Waiting ...') self.loop.draw_screen() def _louie_network_ready(self, network): self.log.info('ZWave network is ready : %d nodes were found.' % network.nodes_count) self.log.info('Controller name : %s' % network.controller.node.product_name) self.network = network self.status_bar.update(status='ZWave network is ready') self.loop.draw_screen() self._connect_louie_node_and_value() def _disconnect_louie_node_and_value(self): #pass dispatcher.disconnect(self._louie_group, ZWaveNetwork.SIGNAL_GROUP) dispatcher.disconnect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.disconnect(self._louie_value_update, ZWaveNetwork.SIGNAL_VALUE) dispatcher.disconnect(self._louie_ctrl_message, ZWaveController.SIGNAL_CONTROLLER) def _connect_louie_node_and_value(self): #pass dispatcher.connect(self._louie_group, ZWaveNetwork.SIGNAL_GROUP) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(self._louie_value_update, ZWaveNetwork.SIGNAL_VALUE) dispatcher.connect(self._louie_ctrl_message, ZWaveController.SIGNAL_CONTROLLER) def _louie_node_update(self, network, node): self.loop.draw_screen() def _louie_value_update(self, network, node, value): self.loop.draw_screen() def _louie_group(self, network, node): self.loop.draw_screen() def _louie_ctrl_message(self, state, message, network, controller): #self.status_bar.update(status='Message from controller: %s : %s' % (state,message)) self.status_bar.update(status='Message from controller: %s' % (message)) self.loop.draw_screen()
elif arg.startswith("--sniff"): temp, sniff = arg.split("=") sniff = float(sniff) elif arg.startswith("--help"): print("help : ") print(" --device=/dev/yourdevice ") print(" --log=Info|Debug") #Define some manager options options = ZWaveOption(device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level('Debug') options.set_logging(True) options.lock() def louie_network_started(network): print("Hello from network : I'm started : homeid %0.8x - %d nodes were found." % \ (network.home_id, network.nodes_count)) def louie_network_failed(network): print("Hello from network : can't load :(.") def louie_network_ready(network): print("Hello from network : I'm ready : %d nodes were found." %
class MainWindow(Screen): def __init__(self, device=None, footer=True, loglevel="Info", user_path=".", config_path=None): Screen.__init__(self) self.device = device self.footer_display = footer self.loglevel = logging.INFO self.loglevel_ow = loglevel self.user_path = user_path self.config_path = config_path self._define_log() self._define_screen() self._connect_louie() self._start_network() def _define_log(self): hdlr = logging.FileHandler('ozwsh.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) if self.loglevel_ow == "Debug": self.loglevel = logging.DEBUG ozwlog = logging.getLogger('openzwave') ozwlog.setLevel(self.loglevel) ozwlog.addHandler(hdlr) lozwlog = logging.getLogger('libopenzwave') lozwlog.setLevel(self.loglevel) lozwlog.addHandler(hdlr) self.log = logging.getLogger('pyozwman') self.log.setLevel(self.loglevel) self.log.addHandler(hdlr) self.log.info("=" * 15 + " start " + "=" * 15) def _define_screen(self): self._palette = [("title", "yellow", "dark cyan"), ("keys", "dark blue", "light gray"), ("message", "light cyan", "dark green"), ("linenr", "light blue", "dark cyan"), ("input", "light gray", "black"), ("input2", "dark red", "light gray"), ("focus", "black", "light gray", "bold"), ("dialog", "black", "light gray", "bold"), ("file", "light green", "dark blue"), ("errortxt", "dark red", "dark blue"), ("selectedfile", "yellow", "dark blue"), ("selectedfocus", "yellow", "light gray", "bold"), ("dir", "light gray", "dark blue"), ("fileedit", "light green", "dark red"), ('edit', 'yellow', 'dark blue'), ('body', 'default', 'default'), ('foot', 'dark cyan', 'dark blue', 'bold'), ('shadow', 'white', 'black'), ('border', 'black', 'dark blue'), ('error', 'black', 'dark red'), ('FxKey', 'light cyan', 'dark blue', 'underline')] self.network = None self.controller = None self.root_box = RootBox(self, None, "body") self.stat_box = StatBox(self, self.root_box, "body") self.controller_box = ControllerBox(self, self.root_box, "body") self.scenes_box = ScenesBox(self, self.root_box, "body") self.scene_box = SceneBox(self, self.scenes_box, "body") self.nodes_box = NodesBox(self, self.root_box, "body") self.switches_box = SwitchesBox(self, self.nodes_box, "body") self.dimmers_box = DimmersBox(self, self.nodes_box, "body") self.sensors_box = SensorsBox(self, self.nodes_box, "body") self.node_box = NodeBox(self, self.nodes_box, "body") self.values_box = ValuesBox(self, self.node_box, "body") self.groups_box = GroupsBox(self, self.node_box, "body") self.status_bar = StatusBar(self) self.header_bar = HeaderBar(self) self.framefocus = 'footer' self._active_box = self.root_box self.frame = urwid.Frame(urwid.AttrWrap(self.active_box, 'body'), \ header=self.header_bar,\ footer=self.status_bar, \ focus_part=self.framefocus) self.active_box = self.root_box self.loop = urwid.MainLoop(self.frame, \ self._palette, \ unhandled_input=self._unhandled_input) @property def active_box(self): """ Gets the number of association groups reported by this node. :rtype: int """ return self._active_box @active_box.setter def active_box(self, value): """ Gets the number of association groups reported by this node. :rtype: int """ self._active_box = value self.frame.set_body(self._active_box) self.header_bar.update(self._active_box.walker.fullpath()) def exit(self): """ Quit the programm Clean network properly and exit """ self.network.write_config() self.network.stop() self.options.destroy() raise urwid.ExitMainLoop() def execute(self, command): """ Parse an execute a commande """ #if wait_for_network == True: # self.status_bar.set_command("Network is not ready. Please wait.") # return True command = command.strip() if command.startswith('ls'): if ' ' in command: cmd, options = command.split(' ') else: options = "" options = options.strip() self.active_box.walker.ls(options) self.status_bar.set_command("") return True elif command.startswith('exit'): self.exit() elif command.startswith('cd'): if ' ' in command: cmd, path = command.split(' ', 1) else: path = "/" path = path.strip() if self.active_box.walker.exist(path): self.active_box = self.active_box.walker.cd(path) self.active_box.walker.ls("") self.status_bar.set_command("") self.log.info(" self.active_box %s" % self.active_box.walker.path) return True elif path == "/": self.active_box = self.root_box self.active_box.walker.ls("") self.status_bar.set_command("") self.log.info(" self.active_box %s" % self.active_box.walker.path) return True else: self.status_bar.update(status='Unknown directory "%s"' % path) return False elif command.startswith('send'): if ' ' in command: cmd, value = command.split(' ', 1) else: self.status_bar.update(status='Usage : send <command>') return False value = value.strip() if len(value) == 0: self.status_bar.update(status='Usage : send <command>') return False if self.active_box.walker.send(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False elif command.startswith('create'): if ' ' in command: cmd, value = command.split(' ', 1) else: self.status_bar.update(status='Usage : create <value>') return False value = value.strip() if len(value) == 0: self.status_bar.update(status='Usage : create <value>') return False if self.active_box.walker.create(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False elif command.startswith('delete'): if ' ' in command: cmd, value = command.split(' ', 1) else: self.status_bar.update(status='Usage : delete <value>') return False value = value.strip() if len(value) == 0: self.status_bar.update(status='Usage : delete <value>') return False if self.active_box.walker.delete(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False elif command.startswith('activate'): if ' ' in command: cmd, value = command.split(' ', 1) else: self.status_bar.update(status='Usage : activate <value>') return False value = value.strip() if len(value) == 0: self.status_bar.update(status='Usage : activate <value>') return False if self.active_box.walker.activate(value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False elif command.startswith('set'): if ' ' in command: cmd, end = command.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : set <field> to <value>') return False end = end.strip() field, end = end.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : set <field> to <value>') return False end = end.strip() to, value = end.split(' ', 1) if len(value) == 0 or to != "to": self.status_bar.update( status='Usage : set <field> to <value>') return False value = value.strip() if self.active_box.walker.set(field, value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False else: self.status_bar.update(status='Usage : set <field> to <value>') return False elif command.startswith('poll'): if ' ' in command: cmd, end = command.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : poll <value> to <intensity>') return False end = end.strip() field, end = end.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : poll <value> to <intensity>') return False end = end.strip() to, value = end.split(' ', 1) if len(value) == 0 or to != "to": self.status_bar.update( status='Usage : poll <value> to <intensity>') return False value = value.strip() if self.active_box.walker.poll(field, value): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False else: self.status_bar.update( status='Usage : poll <value> to <intensity>') return False elif command.startswith('add'): if ' ' in command: cmd, end = command.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : add <value> to <list>') return False end = end.strip() field, end = end.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : add <value> to <list>') return False end = end.strip() to, value = end.split(' ', 1) if len(value) == 0 or to != "to": self.status_bar.update( status='Usage : add <value> to <list>') return False value = value.strip() if self.active_box.walker.add(value, field): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False else: self.status_bar.update(status='Usage : add <value> to <list>') return False elif command.startswith('remove'): if ' ' in command: cmd, end = command.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : remove <value> from <list>') return False end = end.strip() field, end = end.split(' ', 1) if len(end) == 0 or ' ' not in end: self.status_bar.update( status='Usage : remove <value> from <list>') return False end = end.strip() to, value = end.split(' ', 1) if len(value) == 0 or to != "from": self.status_bar.update( status='Usage : remove <value> from <list>') return False value = value.strip() if self.active_box.walker.remove(value, field): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: return False else: self.status_bar.update( status='Usage : remove <value> from <list>') return False elif command.startswith('reset'): if ' ' in command: cmd, state = command.split(' ', 1) state = state.strip() if len(state) == 0: self.status_bar.update(status='Usage : reset soft|hard') return False if self.active_box.walker.reset(state): self.active_box.walker.ls("") self.status_bar.set_command("") return True else: self.status_bar.update(status='Unknowm state "%s"' % state) return False else: self.status_bar.update(status='Unknown command "%s"' % command) return False def _unhandled_input(self, key): if key == 'esc': self.exit() elif key == 'tab' or key == 'shift tab': if self.framefocus == 'footer': self.framefocus = 'body' else: self.framefocus = 'footer' self.frame.set_focus(self.framefocus) return True elif key == 'enter': self.log.info('handled: %s' % repr(key)) cmd = self.status_bar.get_command() self.execute(cmd) return True elif key == 'f5': self.refresh_nodes() return True else: self.log.info('unhandled: %s' % repr(key)) def _start_network(self): #Define some manager options self.options = ZWaveOption(self.device, \ config_path=self.config_path, \ user_path=self.user_path, cmd_line="") self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level(self.loglevel_ow) self.options.set_logging(True) self.options.lock() self.network = ZWaveNetwork(self.options, self.log, kvals=False) self.status_bar.update(status='Start Network') def _connect_louie(self): dispatcher.connect(self._louie_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self._louie_network_resetted, ZWaveNetwork.SIGNAL_NETWORK_RESETTED) dispatcher.connect(self._louie_network_awaked, ZWaveNetwork.SIGNAL_NETWORK_AWAKED) dispatcher.connect(self._louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self._louie_network_stopped, ZWaveNetwork.SIGNAL_NETWORK_STOPPED) def _louie_network_started(self, network): self.log.info('OpenZWave network is started : homeid %0.8x - %d nodes were found.' % \ (network.home_id, network.nodes_count)) self.network = network self.status_bar.update( status='OpenZWave network is started ... Waiting ...') self.loop.draw_screen() def _louie_network_resetted(self, network): self.log.info('OpenZWave network is resetted.') self.network = None #self._disconnect_louie_node_and_value() self.status_bar.update( status='OpenZWave network was resetted ... Waiting ...') self.loop.draw_screen() def _louie_network_stopped(self, network): self.log.info('OpenZWave network is stopped.') self.network = None self.status_bar.update( status='OpenZWave network was stopped ... please quit') self.loop.draw_screen() def _louie_network_awaked(self, network): self.log.info('OpenZWave network is awaked.') self.network = network self.status_bar.update( status='OpenZWave network is awaked ... Waiting ...') self.loop.draw_screen() def _louie_network_ready(self, network): self.log.info('ZWave network is ready : %d nodes were found.' % network.nodes_count) self.log.info('Controller name : %s' % network.controller.node.product_name) self.network = network wait_for_network = False self.status_bar.update(status='ZWave network is ready') self.loop.draw_screen() self._connect_louie_node_and_value() def _disconnect_louie_node_and_value(self): #pass dispatcher.disconnect(self._louie_group, ZWaveNetwork.SIGNAL_GROUP) dispatcher.disconnect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.disconnect(self._louie_value_update, ZWaveNetwork.SIGNAL_VALUE) dispatcher.disconnect(self._louie_ctrl_message, ZWaveController.SIGNAL_CONTROLLER) def _connect_louie_node_and_value(self): #pass dispatcher.connect(self._louie_group, ZWaveNetwork.SIGNAL_GROUP) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(self._louie_value_update, ZWaveNetwork.SIGNAL_VALUE) dispatcher.connect(self._louie_ctrl_message, ZWaveController.SIGNAL_CONTROLLER) def _louie_node_update(self, network, node): self.loop.draw_screen() def _louie_value_update(self, network, node, value): self.loop.draw_screen() def _louie_group(self, network, node): self.loop.draw_screen() def _louie_ctrl_message(self, state, message, network, controller): #self.status_bar.update(status='Message from controller: %s : %s' % (state,message)) self.status_bar.update(status='Message from controller: %s' % (message)) self.loop.draw_screen()
elif arg.startswith("--sniff"): temp,sniff = arg.split("=") sniff = float(sniff) elif arg.startswith("--help"): print("help : ") print(" --device=/dev/yourdevice ") print(" --log=Info|Debug") #Define some manager options options = ZWaveOption(device, \ config_path="../python-openzwave/openzwave/config", \ user_path=".", cmd_line="") options.set_log_file("OZW_Log.log") options.set_append_log_file(False) options.set_console_output(False) options.set_save_log_level(log) options.set_logging(True) options.lock() def louie_network_started(network): print("Hello from network : I'm started : homeid {:08x} - {} nodes were found.".format(network.home_id, network.nodes_count)) def louie_network_failed(network): print("Hello from network : can't load :(.") def louie_network_ready(network): print("Hello from network : I'm ready : {} nodes were found.".format(network.nodes_count)) print("Hello from network : my controller is : {}".format(network.controller)) dispatcher.connect(louie_node_update, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(louie_value_update, ZWaveNetwork.SIGNAL_VALUE)
class ZStickInterface(object): def __init__(self): self.sensor_events = [] self.device = "/dev/ttyACM0" config_path = "plugins/python-openzwave/openzwave/config" user_path = "plugins/python-openzwave/config" # If using older Z-sticks, use the below device: # self.device = "/dev/ttyUSB0" # Change config paths where appropriate self.options = ZWaveOption(self.device, config_path=config_path, user_path=user_path, cmd_line="") # Turn off ozw console output self.options.set_console_output(False) self.options.set_save_log_level("Info") self.options.set_logging(False) self.options.lock() self.manager = libopenzwave.PyManager() self.manager.create() self.manager.addWatcher(self.event_callback) self.manager.addDriver(self.device) print("Starting Z-Wave Network...") self.network = ZWaveNetwork(self.options, log=None) # Wait for network to start while not self.network.state >= self.network.STATE_AWAKED: time.sleep(1) print("Z-Wave Network Started") def toggle_switch(self, node_id): try: in_work_node = self.network.nodes[node_id] switch_val = in_work_node.get_switches().keys()[0] if in_work_node.get_switch_state(switch_val): in_work_node.set_switch(switch_val, False) else: in_work_node.set_switch(switch_val, True) except: print("Invalid node id") def switch(self, node_id, state, function): try: in_work_node = self.network.nodes[node_id] if function == "dimmer": switch_val = in_work_node.get_dimmers().keys()[0] if state == "False": in_work_node.set_dimmer(switch_val, 0) elif state == "True": in_work_node.set_dimmer(switch_val, 99) else: in_work_node.set_dimmer(switch_val, int(state)) elif function == "switch": switch_val = in_work_node.get_switches().keys()[0] if state == "False": in_work_node.set_switch(switch_val, False) else: in_work_node.set_switch(switch_val, True) except: print("Invalid node id") def event_callback(self, args): if args["notificationType"] in ("ValueAdded", "ValueChanged"): cmd_class = args["valueId"]["commandClass"] if cmd_class == "COMMAND_CLASS_SENSOR_BINARY": node_id = args["valueId"]["nodeId"] state = args["valueId"]["value"] data = {"node_id": node_id, "state": state} self.sensor_events.append(data) def get_sensor_events(self): last_events = self.sensor_events self.sensor_events = [] return last_events def stop_network(self): self.network.stop()
def _init_controller(): if P.module_imported: device = '{}{}'.format(P.device, P.device_index) L.l.info('Zwave initialising on {}'.format(device)) _stop_net() # Define some manager options try: options = ZWaveOption(device, config_path="../openzwave/config", user_path=".", cmd_line="") options.set_log_file(P.log_file) options.set_append_log_file(True) options.set_console_output(False) # options.set_save_log_level('Debug') # options.set_save_log_level('Info') options.set_save_log_level('Warning') # options.set_save_log_level('Error') options.set_logging(False) #options.set_logging(True) # options.set_poll_interval(5) options.set_save_configuration(True) options.lock() # Create a network object P.network = ZWaveNetwork(options, log=None, autostart=False) dispatcher.connect(louie_network_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(louie_network_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(louie_network_resetted, ZWaveNetwork.SIGNAL_NETWORK_RESETTED) dispatcher.connect(louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(louie_network_stopped, ZWaveNetwork.SIGNAL_NETWORK_STOPPED) dispatcher.connect(louie_network_awaked, ZWaveNetwork.SIGNAL_NETWORK_AWAKED) P.network.start() L.l.info("Waiting for zwave driver") for i in range(0, 120): if P.network.state >= P.network.STATE_STARTED: L.l.info("Zwave driver started") break else: time.sleep(0.1) if P.network.state < P.network.STATE_STARTED: L.l.info( "Can't initialise zwave driver. Look at the logs in {}". format(P.log_file)) return False L.l.info("Home id : {}, Nodes in network : {}".format( P.network.home_id_str, P.network.nodes_count)) L.l.info("Waiting 120 sec for zwave network to become ready") for i in range(0, 240): if P.network.state >= P.network.STATE_READY: break else: time.sleep(0.5) # L.l.info("state = {}".format(P.network.state)) if not P.network.is_ready: L.l.info( "Can't start network! Look at the logs in OZW_Log.log") P.network.stop() return False else: L.l.info("Zwave network is started!") # print nodes for node_id in P.network.nodes: node = P.network.nodes[node_id] try: L.l.info("Node {}={}".format(node_id, node)) # L.l.info("Node {} attrib: model={} man={} prod_name={} prod_id={}".format( # node_id, node.manufacturer_name, node.product_name, node.product_id)) except Exception as ex: pass # not working # P.network.set_poll_interval(milliseconds=3000, bIntervalBetweenPolls=False) # P.network.test(1) variable.USB_PORTS_IN_USE.append(device) return True except ZWaveException as ze: L.l.error('Unable to init zwave, exception={}'.format(ze)) P.device_index += 1 if P.device_index > 3: P.device_index = 0 return False
class ZWaveCommander: def __init__(self, stdscr): self._curAlert = False self._alertStack = list() self._driverInitialized = False self._options = None self._network = None self._listMode = True self._screen = stdscr self._version = '0.1 Beta 1' self._listtop = 0 self._listindex = 0 self._listcount = 0 self._selectedNode = None self._stop = threading.Event() self._keys = { 'A': 'Add', 'B': 'About', 'D': 'Delete', 'R': 'Refresh', 'S': 'Setup', '+': 'Increase', '-': 'Decrease', '1': 'On', '0': 'Off', 'Q': 'Quit' } #self._network = ZWaveWrapper.getInstance(device=self._config['device'], config=self._config['config'], log=None) self._options = ZWaveOption( \ device="/dev/zwave-aeon-s2", \ config_path="openzwave/config", \ user_path=".", \ cmd_line="") self._options.set_log_file("OZW_Log.log") self._options.set_append_log_file(False) self._options.set_save_log_level('Debug') self._options.set_console_output(False) self._options.set_logging(True) self._options.lock() # TODO: add log level to config # TODO: add log enable/disable to config # TODO: logging - can ozw log be redirected to file? If so, we can add ability to view/tail log FORMAT = '%(asctime)s\t%(levelname)s\t%(name)s\t%(message)s' logging.basicConfig(filename='zwaveCommander.log', level=logging.DEBUG, format=FORMAT) self._log = logging.getLogger('ZWaveCommander') self._logbar = '\n%s\n' % ('-' * 60) def main(self): '''Main run loop''' self._log.info('%sZWaveCommander Version %s Starting%s', self._logbar, self._version, self._logbar) self._initCurses(self._screen) try: self._startNetwork() self._runLoop() finally: self._shutdown() def _delayloop(self, context, duration, callback): self._log.debug('thread %s sleeping...', context) time.sleep(duration) self._log.debug('timer %s expired, executing callback %s', context, callback) if context == 'alert': self._curAlert = False if self._alertStack: self._alert(self._alertStack.pop()) if callback is not None: callback() def _handleQuit(self): # TODO: exit confirmation dialog self._log.info('Stop requested') self._stop.set() def _handleRefresh(self): if self._selectedNode: self._network.refresh(self._selectedNode) def _handleOn(self): if self._selectedNode: self._network.setNodeOn(self._selectedNode) def _handleOff(self): if self._selectedNode: self._network.setNodeOff(self._selectedNode) def _handleIncrease(self): if self._selectedNode: curLevel = self._selectedNode.level newLevel = curLevel + 10 if newLevel > 99: newLevel = 99 self._network.setNodeLevel(self._selectedNode, newLevel) def _handleDecrease(self): if self._selectedNode: curLevel = self._selectedNode.level newLevel = curLevel - 10 if newLevel < 0: newLevel = 0 self._network.setNodeLevel(self._selectedNode, newLevel) def _setTimer(self, context, duration, callback): newTimer = threading.Thread(None, self._delayloop, 'cb-thread-%s' % context, (context, duration, callback), {}) newTimer.setDaemon(True) newTimer.start() def _alert(self, text): '''perform program alert''' if not self._curAlert: self._curAlert = True curses.flash() self._screen.addstr( self._screensize[0] - 1, 0, ' {0:{width}}'.format(text, width=self._screensize[1] - 2), curses.color_pair(self.COLOR_ERROR)) self._screen.refresh() self._setTimer('alert', 1, self._redrawMenu) else: self._alertStack.append(text) def _layoutScreen(self): # TODO: handle screen resize on curses.KEY_RESIZE in loop (tear down, re-calculate, and re-build) # top 5 lines (fixed): system info (including list header) # bottom line (fixed): menu/status # remaining top half: item list (scrolling) # remaining bottom half: split - left half=static info, right half=detail (scrolling) # item list: 8 columns. All column widths here are padded with 1 char space (except col 0, which is always 1 char) # c0=1 char fixed (select indicator) # c1=4 char fixed (id) # c2=10 char min (name) # c3=10 char min (location) # c4=20 char min (type) # c5=9 char fixed (state) # c6=7 char fixed (batt) # c7=7 char fixed (signal) # last three columns: 23 chars: are optional and can fall off if space requires it (min width 45) # "min" columns expand evenly to fit remaining space self._screen.clear() self._log.debug("Laying out screen") self._colwidths = [1, 4, 10, 10, 15, 12, 8, 8] self._colheaders = [ '', 'ID', 'Name', 'Location', 'Type', 'State', 'Batt', 'Signal' ] self._detailheaders = ['Info', 'Values', 'Classes', 'Groups', 'Events'] self._flexcols = [2, 3, 4] self._rowheights = [5, 5, 10, 1] self._flexrows = [1, 2] self._deviceValueColumns = [ 'id', 'commandClass', 'instance', 'index', 'type', 'label', 'value', 'units' ] self._deviceValueWidths = [10, 20, 9, 6, 10, 20, 10, 10] self._sortcolumn = self._colheaders[1] self._detailview = self._detailheaders[0] self._screensize = self._screen.getmaxyx() width = self._screensize[1] height = self._screensize[0] self._log.debug('Screen is %d wide by %d high', width, height) # Update dynamic column widths for device list self._log.debug('Initial column widths are: %s', self._colwidths) cwid = 0 for i in self._colwidths: cwid += i flexwidth = width - cwid if flexwidth > 0: adder = divmod(flexwidth, len(self._flexcols)) for i in self._flexcols: self._colwidths[i] += adder[0] self._colwidths[self._flexcols[-1]] += adder[1] self._log.debug('Adjusted column widths are: %s', self._colwidths) # Update dynamic row heights for screen sections self._log.debug('Initial row heights are: %s', self._rowheights) cht = 0 for i in self._rowheights: cht += i flexheight = height - cht if flexheight > 0: adder = divmod(flexheight, len(self._flexrows)) for i in self._flexrows: self._rowheights[i] += adder[0] self._rowheights[self._flexrows[-1]] += adder[1] self._log.debug('Adjusted row heights are: %s', self._rowheights) if curses.has_colors(): self._log.debug( 'Curses initialized: %d colors and %d color pairs available', curses.COLORS, curses.COLOR_PAIRS) else: self._log.debug('Curses initialized, but no colors are available') self._listpad = curses.newpad(256, 256) self._detailpads = { 'Info': curses.newpad(self._rowheights[2], self._screensize[1]), 'Values': curses.newpad(128, self._screensize[1]), 'Classes': curses.newpad(128, self._screensize[1]), 'Groups': curses.newpad(self._rowheights[2], self._screensize[1]), 'Events': curses.newpad(256, self._screensize[1]) } self._detailpos = dict() for k in self._detailpads.iterkeys(): self._detailpos[k] = 0 self._detailtop = self._rowheights[0] + self._rowheights[1] + 2 self._detailbottom = self._detailtop + self._rowheights[2] - 3 self._updateColumnHeaders() def _initCurses(self, stdscr): '''Configure ncurses application-specific environment (ncurses has already been initialized)''' curses.curs_set(0) # Re-define color attributes... self.COLOR_NORMAL = 1 self.COLOR_HEADER_NORMAL = 2 self.COLOR_HEADER_HI = 3 self.COLOR_ERROR = 4 self.COLOR_CRITICAL = 5 self.COLOR_WARN = 6 self.COLOR_OK = 7 curses.init_pair( self.COLOR_NORMAL, curses.COLOR_WHITE, curses.COLOR_BLACK ) # normal (selected row is inverted, disabled/sleep is dim) curses.init_pair(self.COLOR_HEADER_NORMAL, curses.COLOR_BLACK, curses.COLOR_GREEN) # header normal curses.init_pair(self.COLOR_HEADER_HI, curses.COLOR_WHITE, curses.COLOR_CYAN) # header hi curses.init_pair(self.COLOR_ERROR, curses.COLOR_YELLOW, curses.COLOR_RED) # error text curses.init_pair(self.COLOR_CRITICAL, curses.COLOR_RED, curses.COLOR_BLACK) # critical curses.init_pair(self.COLOR_WARN, curses.COLOR_YELLOW, curses.COLOR_BLACK) # warn curses.init_pair(self.COLOR_OK, curses.COLOR_GREEN, curses.COLOR_BLACK) # ok self._layoutScreen() def _handleSetup(self): self._alert('handleSetup not yet implemented') def _checkIfInitialized(self): if not self._driverInitialized: msg = 'Unable to initialize driver - check configuration' self._alert(msg) self._log.warning(msg) self._handleSetup() else: self._log.info('OpenZWave initialized successfully.') def _notifyDriverReady(self, network, controller): self._log.info( 'OpenZWave Driver is Ready; homeid is %0.8x. %d nodes were found.' % (network.home_id, network.nodes_count)) self._driverInitialized = True self._addDialogText( 2, 'Driver initialized with homeid %0.8x' % network.home_id) self._addDialogText(3, 'Node Count is now %' % network.nodes_count) def _notifyNodeAdded(self, network, node): self._addDialogText(3, 'Node Count is now %s'.format(network.nodes_count)) self._updateSystemInfo() def _redrawAll(self): self._clearDialog() self._updateSystemInfo() self._updateDeviceList() self._updateColumnHeaders() self._updateDeviceDetail() def _notifyNetworkReady(self, network, controller): self._log.info('OpenZWave Initialization Complete.') self._alert('OpenZWave Initialization Complete.') self._redrawAll() def _notifyNetworkFailed(self, network): self._log.info('OpenZWave Initialization failed.') self._alert('OpenZWave Initialization failed.') self._redrawAll() def _notifyNodeReady(self, network, node): self._readyNodeCount += 1 self._addDialogText(2, 'OpenZWave is querying associated devices') self._addDialogText(3, 'Node %s is now ready' % node.node_id) self._addDialogProgress(5, self._readyNodeCount, network.nodes_count) self._updateDeviceList() def _notifyValueChanged(self, signal, **kw): nodeId = kw['nodeId'] self._log.debug( 'Got value changed notification for node {0}'.format(nodeId)) # TODO: this is very heavy handed - just update appropriate elements self._updateDeviceList() self._updateDeviceDetail() def _initDialog(self, height, width, buttons=('OK', ), caption=None): self._dialogpad = curses.newpad(height, width) self._dialogpad.bkgd(0x94, curses.color_pair(self.COLOR_HEADER_HI)) self._dialogpad.clear() self._dialogpad.box() if caption: lh = (width / 2) - (len(caption) / 2) - 1 self._dialogpad.addstr( 0, lh, ' {0} '.format(caption), curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT) if buttons: if len(buttons) > 1: bwid = 0 for bcap in buttons: if len(bcap) > bwid: bwid = len(bcap) cellwid = (width - 4) / len(buttons) lpad = (cellwid - bwid) / 2 - 1 rpad = cellwid - bwid - lpad - 1 self._dialogpad.move(height - 2, 1) else: bwid = len(buttons[0]) lpad = rpad = 1 self._dialogpad.move(height - 2, (width / 2) - (bwid / 2) - 2) for button in buttons: self._dialogpad.addstr( '{0:{wlpad}}<{1:^{wbwid}}>{0:{wrpad}}'.format('', button, wlpad=lpad, wbwid=bwid, wrpad=rpad)) dt = (self._screensize[0] / 2) - (height / 2) dl = (self._screensize[1] / 2) - (width / 2) dc = padcoords(sminrow=dt, smincol=dl, smaxrow=dt + height - 1, smaxcol=dl + width - 1) self._dialogcoords = dc self._dialogpad.overlay(self._screen, 0, 0, dc.sminrow, dc.smincol, dc.smaxrow, dc.smaxcol) self._screen.refresh() def _clearDialog(self): del self._dialogpad self._dialogpad = None self._dialogcoords = None self._screen.touchwin() self._screen.refresh() def _updateDialog(self): if self._dialogpad: self._screen.refresh() dc = self._dialogcoords self._dialogpad.refresh(0, 0, dc.sminrow, dc.smincol, dc.smaxrow, dc.smaxcol) def _addDialogText(self, row, text, align='^'): if self._dialogpad: self._dialogpad.addstr( row, 1, '{0:{aln}{wid}}'.format(text, aln=align, wid=self._dialogpad.getmaxyx()[1] - 2)) self._updateDialog() def _addDialogProgress(self, row, current, total, showPercent=True, width=None): if self._dialogpad: dc = self._dialogcoords if width is None: width = (dc.smaxcol - dc.smincol) * 2 / 3 pct = float(current) / float(total) filled = int(pct * float(width)) lh = ((dc.smaxcol - dc.smincol) / 2) - (width / 2) self._dialogpad.addch( row, lh - 1, '[', curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._dialogpad.addch( row, lh + width, ']', curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._dialogpad.addstr(row, lh, ' ' * width, curses.color_pair(self.COLOR_NORMAL)) self._dialogpad.addstr( row, lh, '|' * filled, curses.color_pair(self.COLOR_OK) | curses.A_BOLD) if showPercent: pctstr = '{0:4.0%}'.format(pct) lh = ((dc.smaxcol - dc.smincol) / 2) - (len(pctstr) / 2) self._dialogpad.addstr( row, lh, pctstr, curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._updateDialog() def _startNetwork(self): dispatcher.connect(self._notifyDriverReady, ZWaveNetwork.SIGNAL_DRIVER_READY) dispatcher.connect(self._notifyNetworkReady, ZWaveNetwork.SIGNAL_NETWORK_READY) dispatcher.connect(self._notifyNetworkFailed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self._notifyNodeReady, ZWaveNetwork.SIGNAL_NODE_READY) dispatcher.connect(self._notifyValueChanged, ZWaveNetwork.SIGNAL_VALUE_CHANGED) dispatcher.connect(self._notifyNodeAdded, ZWaveNetwork.SIGNAL_NODE_ADDED) self._initDialog(10, 60, ['Cancel'], 'Progress') self._addDialogText(2, 'Initializing OpenZWave') self._log.info('Initializing OpenZWave') self._network = ZWaveNetwork(self._options, log=self._log) #self._network = ZWaveWrapper.getInstance(device=self._config['device'], config=self._config['config'], log=None) self._setTimer('initCheck', 3, self._checkIfInitialized) while not self._stop.isSet() and not self._driverInitialized: time.sleep(0.1) # TODO: handle keys here... cancel/etc def _runLoop(self): while not self._stop.isSet(): key = self._screen.getch() if key == curses.KEY_DOWN: self._switchItem(1) elif key == curses.KEY_UP: self._switchItem(-1) elif key == curses.KEY_LEFT: self._switchTab(-1) elif key == curses.KEY_RIGHT: self._switchTab(1) elif key == 0x09: self._nextMode() elif key is not None: self._handleMnemonic(key) def _handleMnemonic(self, key): for mnemonic, func in self._keys.iteritems(): if key == ord(mnemonic[0].lower()) or key == ord( mnemonic[0].upper()): funcname = '_handle%s' % func try: method = getattr(self, funcname) method() except AttributeError as ex: msg = 'No method named [%s] defined!' % funcname self._log.warn('handleMnemonic: %s', msg) self._log.warn('handleMnemonic Exception Details: %s', str(ex)) self._alert(msg) break def _resetDetailPos(self): for p in self._detailpos.iterkeys(): self._detailpos[p] = 0 def _switchItem(self, delta): if self._listMode: n = self._listindex + delta if n in range(0, self._listcount): self._listindex = n self._updateDeviceList( ) # TODO: we don't really need to redraw everything when selection changes self._resetDetailPos() self._updateDeviceDetail() else: self._detailpos[self._detailview] += delta self._updateDeviceDetail() def _switchTab(self, delta): if self._listMode: i = self._colheaders.index(self._sortcolumn) i += delta if i > len(self._colheaders) - 1: i = 1 elif i < 1: i = len(self._colheaders) - 1 self._sortcolumn = self._colheaders[i] else: i = self._detailheaders.index(self._detailview) i += delta if i > len(self._detailheaders) - 1: i = 0 elif i < 0: i = len(self._detailheaders) - 1 self._detailview = self._detailheaders[i] self._updateColumnHeaders() self._updateDeviceList() self._updateDeviceDetail() def _nextMode(self): self._listMode = not self._listMode self._updateColumnHeaders() def _shutdown(self): # TODO: handle orderly shutdown pass def _rightPrint(self, row, data, attrs=None): if attrs is None: attrs = curses.color_pair(self.COLOR_NORMAL) self._screen.addstr(row, self._screensize[1] - len(data), data, attrs) def _updateSystemInfo(self): self._screen.addstr(0,1,'%s on %s' % \ (self._network.controller.description, self._network.controller.device), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.addstr(1,1,'Home ID 0x%0.8x' % \ (self._network.self._network.home_id), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.move(2, 1) self._screen.addstr('%s Registered Nodes' % \ (self._network.nodes_count), \ curses.color_pair(self.COLOR_NORMAL)) self._screen.addstr(' (%s Sleeping)' % \ (self._network.sleeping_nodes_count), \ curses.color_pair(self.COLOR_NORMAL) | curses.A_DIM) self._rightPrint(0, 'Library' % \ (self._network.controller.library_description)) self._rightPrint(1, 'Python Library Version %s' % \ (self._network.controller.python_library_version)) self._screen.refresh() def _updateColumnHeaders(self): self._screen.move(4, 0) for text, wid in zip(self._colheaders, self._colwidths): clr = curses.color_pair(self.COLOR_HEADER_NORMAL ) if self._listMode else curses.color_pair( self.COLOR_NORMAL) | curses.A_STANDOUT if text == self._sortcolumn: clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD self._screen.addstr('{0:<{width}}'.format(text, width=wid), clr) self._screen.move(self._rowheights[0] + self._rowheights[1] + 1, 0) clr = curses.color_pair(self.COLOR_HEADER_NORMAL ) if not self._listMode else curses.color_pair( self.COLOR_NORMAL) | curses.A_STANDOUT self._screen.addstr( '{0:{width}}'.format('', width=self._screensize[1]), clr) self._screen.move(self._rowheights[0] + self._rowheights[1] + 1, 0) for text in self._detailheaders: clr = curses.color_pair( self.COLOR_HEADER_NORMAL ) if not self._listMode else curses.color_pair( self.COLOR_NORMAL) | curses.A_STANDOUT if text == self._detailview: clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD wid = len(text) self._screen.addstr(' {0:<{width}} '.format(text, width=wid), clr) def _fixColumn(self, text, width, align='<'): retval = '{0:{aln}{wid}}'.format(text, aln=align, wid=width) if len(retval) > width: retval = retval[:width] return retval def _getListItemColor(self, drawSelected): return curses.color_pair(self.COLOR_NORMAL) | curses.A_STANDOUT if drawSelected \ else curses.color_pair(self.COLOR_NORMAL) def _drawMiniBar(self, value, minValue, maxValue, drawWidth, drawSelected, drawPercent=False, colorLevels=None): clr = self._getListItemColor(drawSelected) pct = float(value) / float(maxValue) dw = drawWidth - 2 filled = int(pct * float(dw)) fillcolor = clr if not drawSelected: fillcolor = curses.color_pair(self.COLOR_OK) if colorLevels: if pct <= colorLevels.error: fillcolor = curses.color_pair(self.COLOR_CRITICAL) elif pct <= colorLevels.warning: fillcolor = curses.color_pair(self.COLOR_WARN) self._listpad.addch('[', clr | curses.A_BOLD) self._listpad.addstr('|' * filled, fillcolor) self._listpad.addstr(' ' * (dw - filled), clr) self._listpad.addch(']', clr | curses.A_BOLD) # TODO: draw percent text if requested def _drawNodeStatus(self, node, drawSelected): clr = self._getListItemColor(drawSelected) if node.is_sleeping: self._listpad.addstr( self._fixColumn('(sleeping)', self._colwidths[5]), clr | curses.A_LOW) elif node.has_command_class(0x76): # lock self._listpad.addstr( self._fixColumn('Locked' if node.is_locked else 'Unlocked', self._colwidths[5]), clr) elif node.has_command_class(0x26): # multi-level switch self._drawMiniBar(node.level, 0, 99, self._colwidths[5], drawSelected) elif node.has_command_class(0x25): # binary switch self._listpad.addstr( self._fixColumn('ON' if node.is_on else 'OFF', self._colwidths[5]), clr) else: self._listpad.addstr(self._fixColumn('OK', self._colwidths[5]), clr) def _drawBatteryStatus(self, node, drawSelected): clr = self._getListItemColor(drawSelected) if node.has_command_class(0x80): self._drawMiniBar(node.batteryLevel, 0, 100, self._colwidths[6], drawSelected, colorLevels=colorlevels(error=0.10, warning=0.40)) else: self._listpad.addstr(self._fixColumn('', self._colwidths[6]), clr) def _drawSignalStrength(self, node, drawSelected): clr = self._getListItemColor(drawSelected) self._listpad.addstr(self._fixColumn('', self._colwidths[7]), clr) def _drawDeviceNodeLine(self, node, drawSelected): clr = self._getListItemColor(drawSelected) self._listpad.addstr(' ', clr) self._listpad.addstr(self._fixColumn(node.id, self._colwidths[1]), clr) self._listpad.addstr(self._fixColumn(node.name, self._colwidths[2]), clr) self._listpad.addstr( self._fixColumn(node.location, self._colwidths[3]), clr) self._listpad.addstr( self._fixColumn(node.productType, self._colwidths[4]), clr) self._drawNodeStatus(node, drawSelected) self._drawBatteryStatus(node, drawSelected) self._drawSignalStrength(node, drawSelected) def _updateDeviceList(self): self._listcount = self._network.nodes_count idx = 0 for node in self._network._nodes.itervalues(): if idx == self._listindex: self._selectedNode = node self._listpad.move(idx, 0) self._drawDeviceNodeLine(node, idx == self._listindex) idx += 1 ctop = self._rowheights[0] listheight = self._rowheights[1] if self._listindex - self._listtop > listheight: self._listtop = self._listindex - listheight elif self._listindex < self._listtop: self._listtop = self._listindex self._screen.refresh() self._listpad.refresh(self._listtop, 0, ctop, 0, ctop + listheight, self._screensize[1] - 1) self._updateDialog() def _redrawDetailTab(self, pad): self._screen.refresh() pad.refresh(0, 0, self._detailtop, 0, self._detailbottom, self._screensize[1] - 1) def _updateDetail_Values(self, pad): # Draw column header clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD pad.addstr(0, 0, '{0:<{width}}'.format(' ', width=self._screensize[1]), clr) pad.move(0, 1) for text, wid in zip(self._deviceValueColumns, self._deviceValueWidths): pad.addstr('{0:<{width}}'.format(text.title(), width=wid), clr) node = self._selectedNode if node and node.values: # Grab all items except for configuration values (they have their own tab) vset = list() for value in node.values.itervalues(): if value.valueData: vset.append(value) # Sort the resulting set: (1) command class, (2) instance, (3) index s = sorted(sorted(sorted( vset, key=lambda value: value.getValue('index')), key=lambda value: value.getValue('instance')), key=lambda value: value.getValue('commandClass')) if self._detailpos[self._detailview] >= len(s): self._detailpos[self._detailview] = len(s) - 1 i = 0 for value in s: vdic = value.valueData pad.move(i + 1, 0) # TODO: reset detail position on parent item change drawSelected = self._detailpos['Values'] == i clr = self._getListItemColor(drawSelected) pad.addstr(' ' * self._screensize[1], clr) pad.move(i + 1, 1) i += 1 for key, wid in zip(self._deviceValueColumns, self._deviceValueWidths): clr = self._getListItemColor(drawSelected) text = value.getValue(key) # strip 'COMMAND_CLASS_' prefix to save some space if key == 'commandClass' and text.startswith( 'COMMAND_CLASS_'): text = text[14:] # TODO: value decorators (checkbox for Booleans, edit box for others) # decimal: format to 2 places # bool as checkbox # byte as minibar if editable # ints need to be directly edited... # buttons... ? # Draw editable items differently if key == 'value' and not vdic['readOnly'] and drawSelected: clr = curses.color_pair(self.COLOR_ERROR) pad.addstr(self._fixColumn(text, wid), clr) def _updateDetail_Info(self, pad): node = self._selectedNode if node: #baudRate, basic, generic, specific, version, security self._deviceInfoColumns = [ 'id', 'name', 'location', 'capabilities', 'neighbors', 'manufacturer', 'product', 'productType' ] if self._detailpos[self._detailview] >= len( self._deviceInfoColumns): self._detailpos[self._detailview] = len( self._deviceInfoColumns) - 1 editableColumns = ['name', 'location', 'manufacturer', 'product'] i = maxwid = 0 for name in self._deviceInfoColumns: maxwid = len(name) if len(name) > maxwid else maxwid colwidth = maxwid + 2 clr = self._getListItemColor(False) clr_rw = curses.color_pair(self.COLOR_ERROR) clr_ro = self._getListItemColor(True) clr_col = curses.color_pair(self.COLOR_OK) # TODO: If editable, should be textpad for column in self._deviceInfoColumns: val = str(getattr(node, column)) pad.move(i + 1, 1) pad.addstr( '{0:>{width}}'.format(column.title() + ':', width=colwidth), clr_col) selected = i == self._detailpos[self._detailview] thisclr = clr if selected: thisclr = clr_rw if column in editableColumns else clr_ro i += 1 pad.addstr(' ') pad.addstr('{0:<{width}}'.format(val, width=30), thisclr) def _updateDetail_Classes(self, pad): clr = curses.color_pair(self.COLOR_HEADER_HI) | curses.A_BOLD pad.addstr( 0, 0, '{0:<{width}}'.format(' CommandClass', width=self._screensize[1]), clr) node = self._selectedNode if node: if self._detailpos[self._detailview] >= len(node.commandClasses): self._detailpos[self._detailview] = len( node.commandClasses) - 1 i = 0 for cc in node.commandClasses: pad.addstr( i + 1, 0, ' {0:<{width}}'.format( self._network.getCommandClassName(cc), width=30), self._getListItemColor( i == self._detailpos[self._detailview])) i += 1 def _updateDetail_Groups(self, pad): pad.addstr(3, 3, 'Group view not yet implemented') # groups tab: # index label maxMembers members # 1 my group 4 1, 2, 4 # Members column is editable - enter comma-separated list? def _updateDetail_Events(self, pad): pad.addstr(3, 3, 'Event view not yet implemented') # event detail tab: # timestamp commandClass notificationType def _updateDeviceDetail(self): # TODO: detail needs to be scrollable, but to accomplish that a couple of changes need to be made. First, the detail header band needs to be moved into a static shared section (above the detail pad); second, a new dict of 'top' positions needs to be created; finally, positioning code needs to be written to correctly offset the pad. pad = self._detailpads[self._detailview] pad.clear() if self._detailpos[self._detailview] < 0: self._detailpos[self._detailview] = 0 funcname = '_updateDetail_{0}'.format(self._detailview) try: method = getattr(self, funcname) method(pad) except AttributeError as ex: msg = 'No method named [%s] defined!' % funcname self._log.warn('_updateDeviceDetail: %s', msg) self._log.warn('_updateDeviceDetail Exception Details: %s', str(ex)) self._alert(msg) self._redrawDetailTab(pad) def _updateMenu(self): menurow = self._screensize[0] - 1 self._screen.addstr(menurow, 0, ' ' * (self._screensize[1] - 1), curses.color_pair(self.COLOR_HEADER_NORMAL)) self._screen.move(menurow, 4) for mnemonic, text in self._keys.iteritems(): self._screen.addstr( ' {0} '.format(mnemonic), curses.color_pair(self.COLOR_NORMAL) | curses.A_BOLD) self._screen.addstr('{0}'.format(text), curses.color_pair(self.COLOR_HEADER_NORMAL)) def _redrawMenu(self): self._updateMenu() self._screen.refresh()
class ZWaveAgent(AbstractAgent): """A Zwave Agent for directly collecting data from a ZWave network. Requires openzwave to be installed (see tools folder) and ZWave Stick to be plugged in""" def __init__(self, configDir, osnInstance): AbstractAgent.__init__(self, configDir, osnInstance) log="Info" # should be read from config later configChanged = False if "zwave_device" not in self.configData: self.configData["zwave_device"] = "/dev/ttyACM0" configChanged = True if configChanged: self.serializeConfig() # handle zwave default device configurations self.zwaveDefaultConfigs = {} self.zwaveDefaultConfigFile = os.path.join(self.configDir, "zwavedefaultconfigs.config.json") self.readZwaveDefaultConfigs() self.device = self.configData["zwave_device"] self.logger.debug("Initiating ZWaveAgent with device %s." % self.device) self.zwaveOptions = "" try: self.zwaveOptions = ZWaveOption(self.device.encode('ascii'), \ config_path=expanduser("~")+"/ozw-install/python-open-zwave/openzwave/config", \ user_path=self.configDir, cmd_line="") self.zwaveOptions.set_log_file("../log/openzwave.log") # Todo: don't hardcode openzwave-path self.zwaveOptions.set_append_log_file(False) self.zwaveOptions.set_console_output(False) self.zwaveOptions.set_save_log_level(log) self.zwaveOptions.set_logging(False) self.zwaveOptions.lock() except BaseException as e: self.logger.info("Error setting up ZWave network. Correct device? Device properly connected? Device is: %s Exception message: %s" % (self.device, e)) self.inDiscoveryMode = False #scanning for available devices and sensors is slightly more complicated here... def networkStarted(self, network): self.logger.info("Network %0.8x started" % network.home_id) def networkFailed(self, network): self.logger.warning("Sorry, Network couldn't be started...") if self.inDiscoveryMode: self.logger("Discovery failed - terminating.") self.stop() def networkReady(self, network): self.logger.info("Network %0.8x is ready - %d nodes were found." % (self.network.home_id, self.network.nodes_count)) self.logger.info("Network controller %s is connected to %s" % (self.network.controller.node.product_name, self.device)) self.logger.info("\nNodes List:") self.logger.info("===========") configChanged = False for node in network.nodes: self.logger.info("Node %s: %s (battery: %s)" % (node, network.nodes[node].product_name, network.nodes[node].get_battery_level())) self.logger.info("Available Command Classes: %s" % network.nodes[node].command_classes) modelString = network.nodes[node].manufacturer_name + " " + network.nodes[node].product_name if node != self.network.controller.node_id: # not for controller node # Should usually only be necessary once in a lifetime for a given network, but repeating it on every startup doesn't ha$ self.configureNode(network, node) for sensor in network.nodes[node].get_sensors(): if ((not self.sensorConfigured(sensor)) and (self.inDiscoveryMode)): # we are in discovery mode and sensor is not configured yet, add default self.addDefaultSensor(sensor, network.nodes[node].get_sensors()[sensor].label, network.nodes[node].get_sensors()[sensor].units, {"sensorModel":modelString}) configChanged = True self.logger.debug("Sensor %s has %s of %s (Unit: %s)" % (sensor, network.nodes[node].get_sensors()[sensor].label, \ network.nodes[node].get_sensor_value(sensor), network.nodes[node].get_sensors()[sensor].units)) if self.inDiscoveryMode: # as discovery is more complicated for Zwave, we have to do it this way. # in discovery Mode, the config including new default configurations is serialized, then the agent Is stopped. if configChanged: # serialize for having all new sensors in config self.serializeConfig() self.isRunning = False # this ensures that runner stops this agent after discovery is completed else: dispatcher.connect(self.nodeUpdate, ZWaveNetwork.SIGNAL_NODE) dispatcher.connect(self.valueUpdate, ZWaveNetwork.SIGNAL_VALUE) def nodeUpdate(self, network, node): # maybe do something valuable here later... self.logger.debug('Received node update from node : %s.' % node) pass def valueUpdate(self, network, node, value): # not sure whether this might produce redundancies in case of one value_id appearing for multiple nodes... # nonetheless, staying with this for the moment self.sendValue(value.value_id, value.data) def configureNode(self,network, node): # Model-specific configuration of node. This definitely needs a complete rewrite later... self.logger.info("Setting specific configuration for product %s (Product ID: %s)..." % (network.nodes[node].product_name, network.nodes[node].product_id)) productId = network.nodes[node].product_id defaultConfig = self.getDefaultDeviceConfiguration(productId) if defaultConfig: # could also be empty in case this product has no default config yet self.logger.debug("Got default config.") for param in network.nodes[node].values.values(): # traverse through available parameters self.logger.debug("Checking if default config exists for %s" % param.value_id) if defaultConfig.has_key("%s" % param.value_id): # is this parameter specified in default config? we take the long value id as key to avoid misinterpretations self.logger.debug("Default config found. Now checking if default config contains a value") if defaultConfig["%s" % param.value_id].has_key("value"): self.logger.debug("Found value. Setting parameter <%s> to %s as specified in default config" % (param.label, defaultConfig["%s" % param.value_id]["value"])) param.data = defaultConfig["%s" % param.value_id]["value"] else: self.logger.info("No default configuration found for device with product id %s - creating dumb template from what is reported..." % productId) newConfig = {} for param in network.nodes[node].values.values(): # traverse through available parameters newConfig["product name"] = network.nodes[node].manufacturer_name + " " + network.nodes[node].product_name newConfig[param.value_id] = {} note = param.label if param.units: note = note + " (" + param.units + ")" newConfig[param.value_id]["note"] = note newConfig[param.value_id]["parameter index"] = param.index newConfig[param.value_id]["value"] = param.data self.zwaveDefaultConfigs["products"][productId] = newConfig self.serializeZwaveDefaultConfigs() def getDefaultDeviceConfiguration(self, productId): self.logger.debug("getting zwave default configs for product id %s" % productId) if self.zwaveDefaultConfigs["products"].has_key(productId): return self.zwaveDefaultConfigs["products"][productId] else: return {} def readZwaveDefaultConfigs(self): self.logger.debug("reading zwave default device configs from %s" % self.zwaveDefaultConfigFile) configChanged = False if os.path.isfile(self.zwaveDefaultConfigFile): # If configFile does not exist yet, default configs will be created and serialized later with open(self.zwaveDefaultConfigFile) as configFileHandle: self.zwaveDefaultConfigs = json.load(configFileHandle) if "products" not in self.zwaveDefaultConfigs: self.zwaveDefaultConfigs["products"]={} configChanged = True if (configChanged): self.serializeZwaveDefaultConfigs() def serializeZwaveDefaultConfigs(self): with open(self.zwaveDefaultConfigFile, "w") as configFileHandle: self.logger.info("Serializing zwave default device configs to %s." % self.zwaveDefaultConfigFile) json.dump(self.zwaveDefaultConfigs, configFileHandle, sort_keys = False, indent = 4, ensure_ascii=False) # data_file.close def run(self): self.isRunning = True #Create a network object self.network = ZWaveNetwork(self.zwaveOptions, autostart=False) #and connect our above handlers to respective events dispatcher.connect(self.networkStarted, ZWaveNetwork.SIGNAL_NETWORK_STARTED) dispatcher.connect(self.networkFailed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) dispatcher.connect(self.networkReady, ZWaveNetwork.SIGNAL_NETWORK_READY) self.network.start() def discoverSensors(self): self.inDiscoveryMode = True # In this case, stuff is slightly more complicated as we have to manage the zwave network, too. # We thus here use the thread's run()-method and terinate once the discovery is complete. self.run() def stop(self): self.network.stop() self.isRunning = False
class MainWindow(Screen): def __init__(self, device=None, footer=False, name=None): Screen.__init__(self) self.device = device self.footer_display = footer self._define_log() self._define_screen() self._connect_louie() self._start_network() def _define_log(self): hdlr = logging.FileHandler('/tmp/urwidcmd.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) self.log = logging.getLogger('ozwman') self.log.addHandler(hdlr) self.log.setLevel(logging.DEBUG) self.log.info("="*15 + " start " + "="*15) def _define_screen(self): self._palette = [("title", "yellow", "dark cyan"), ("keys", "dark blue", "light gray"), ("message", "light cyan", "dark green"), ("linenr", "light blue", "dark cyan"), ("input", "light gray", "black"), ("input2", "dark red", "light gray"), ("focus", "black", "light gray", "bold"), ("dialog", "black", "light gray", "bold"), ("file", "light green", "dark blue"), ("errortxt", "dark red", "dark blue"), ("selectedfile", "yellow", "dark blue"), ("selectedfocus", "yellow", "light gray", "bold"), ("dir", "light gray", "dark blue"), ("fileedit", "light green", "dark red"), ('edit', 'yellow', 'dark blue'), ('body','default', 'default'), ('foot','dark cyan', 'dark blue', 'bold'), ('shadow','white','black'), ('border','black','dark blue'), ('error','black','dark red'), ('FxKey','light cyan', 'dark blue', 'underline')] #self.divider = urwid.Divider("-") self.left_header = LeftHeader() self.right_header = RightHeader() self.details = DetailsWidget(self, "result") #self.menu = MenuWidget(self, "footer") self.network = None #self.nodes_walker = NodesWalker(self, self.network) self.listbox_header = NodeItem() self.listbox = NodesBox(self, "body") self.menu = MenuWidget(self, "value") self.nodes = [] self.status_bar = StatusBar() self.header = urwid.Pile([ #self.divider, urwid.Columns([ ('weight', 2, urwid.AttrWrap(self.left_header, 'reverse')), #('fixed', 1, urwid.Divider("|")), ('weight', 2, urwid.AttrWrap(self.right_header, 'reverse')) ], dividechars=2, min_width=8), DIVIDER, self.listbox_header.get_header() ]) # self.footer_columns = urwid.Columns([ # ('weight', 1, urwid.AttrWrap(self.menu, 'reverse')), # #('fixed', 1, urwid.Divider("|")), # ('weight', 3,urwid.AttrWrap(self.details, 'reverse')) # ], dividechars=2, min_width=8) #self.sub_frame = urwid.Filler(urwid.Frame( \ # urwid.AttrWrap( # self.details, 'sub_frame_body'), \ # header=self.details.header_widget(),\ # footer=self.details.footer_widget(), \ # focus_part="body"), height=9) #self.footer_columns = urwid.Columns([ # ('weight', 1, urwid.AttrWrap(self.menu, 'reverse')), #('fixed', 1, urwid.Divider("|")), # ('weight', 3,urwid.AttrWrap(self.details, 'reverse')) # ], dividechars=2, min_width=8) # self.footer = urwid.Pile([ # DIVIDER, # self.footer_columns, # DIVIDER, # urwid.AttrWrap(self.status_bar, 'reverse'), # #self.divider, # #urwid.AttrWrap(urwid.Text(" > "), 'footer') # ]) self.footer = urwid.Pile([ DIVIDER, urwid.AttrWrap(self.status_bar, 'reverse'), #self.divider, #urwid.AttrWrap(urwid.Text(" > "), 'footer') ]) self.framefocus = 'body' # self.frame = urwid.Frame(urwid.AttrWrap(self.listbox, 'body'), \ # header=self.header,\ # footer=self.footer, \ # focus_part=self.framefocus) self.frame = FrameApp(urwid.AttrWrap(self.listbox, 'body'), \ header=self.header,\ command=(self.menu,1),\ result=(self.details,5),\ # value=self.menu,\ # footer=self.footer, \ log = self.log, \ focus_part=self.framefocus, status_bar=self.footer_display, menu_f=self.footer_display, ) self.frame.set_menu_f(f1="Help",f5="Refresh") self.loop = urwid.MainLoop(self.frame, \ self._palette, \ unhandled_input=self._unhandled_input) def refresh_nodes(self): self.listbox.body.read_nodes(self.network) self.update_node(self.listbox.walker.get_nodeid()) def update_node(self, nodeid): if nodeid != None : self.details.update( \ nodeid=nodeid, \ name=self.network.nodes[nodeid].name, \ location=self.network.nodes[nodeid].location, \ manufacturer=self.network.nodes[nodeid].manufacturer_name, \ product=self.network.nodes[nodeid].product_name, \ neighbors=self.network.nodes[nodeid].neighbors, \ version=self.network.nodes[nodeid].version, \ signal=self.network.nodes[nodeid].max_baud_rate, \ ) self.log.info('Update node id=%d, product name=%s.' % \ (nodeid, self.network.nodes[nodeid].product_name)) def handle_main_key(self, key): if key == 'f5': self.refresh_nodes() else: self.log.info('unhandled: %s' % repr(key)) def _unhandled_input(self, key): if key == 'esc': self.network.write_config() raise urwid.ExitMainLoop() else: self.log.info('unhandled: %s' % repr(key)) def _start_network(self): #Define some manager options self.options = ZWaveOption(self.device, \ config_path="../openzwave/config", \ user_path=".", cmd_line="") self.options.set_log_file("OZW_Log.log") self.options.set_append_log_file(False) self.options.set_console_output(False) self.options.set_save_log_level('Debug') self.options.set_logging(True) self.options.lock() self.network = ZWaveNetwork(self.options, self.log) self.frame.set_status_bar('Start Network') def _connect_louie(self): dispatcher.connect(self._louie_driver_ready, ZWaveNetwork.SIGNAL_DRIVER_READY) dispatcher.connect(self._louie_network_ready, ZWaveNetwork.SIGNAL_NETWORK_READY) #dispatcher.connect(self._notifyNetworkFailed, ZWaveNetwork.SIGNAL_NETWORK_FAILED) #dispatcher.connect(self._notifyNodeReady, ZWaveNetwork.SIGNAL_NODE_READY) #dispatcher.connect(self._notifyValueChanged, ZWaveNetwork.SIGNAL_VALUE_CHANGED) #dispatcher.connect(self._notifyNodeAdded, ZWaveNetwork.SIGNAL_NODE_ADDED) def _louie_driver_ready(self, network, controller): self.log.info('OpenZWave driver is ready : homeid %0.8x - %d nodes were found.' % \ (network.home_id, network.nodes_count)) self.network = network self.left_header.update_controller("%s on %s" % \ (network.controller.node.product_name, self.device)) self.left_header.update_homeid(network.home_id_str) self.left_header.update_nodes(network.nodes_count,0) self.right_header.update(network.controller.library_description, \ network.controller.ozw_library_version, \ network.controller.python_library_version) self.frame.set_status_bar('OpenZWave driver is ready') self.loop.draw_screen() def _louie_network_ready(self, network): self.log.info('ZWave network is ready : %d nodes were found.' % network.nodes_count) self.log.info('Controller name : %s' % network.controller.node.product_name) self.network = network self.left_header.update_controller("%s on %s" % \ (network.controller.node.product_name, self.device)) self.left_header.update_nodes(network.nodes_count,0) #self.set_nodes() self.frame.set_status_bar('ZWave network is ready') self.loop.draw_screen() #self._connect_louie_node() def _connect_louie_node(self): dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_EVENT) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_ADDED) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_NAMING) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_NEW) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_PROTOCOL_INFO) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_READY) dispatcher.connect(self._louie_node_update, ZWaveNetwork.SIGNAL_NODE_REMOVED) def _louie_node_update(self, network, node): self.log.info('Node event %s' % node) self.network = network #self.set_nodes() self.frame.set_status_bar('Node event') self.refresh_nodes() self.loop.draw_screen() def _wrap(self, widget, attr_map): return urwid.AttrMap(widget, attr_map) def rawWrite(self, text): """ Add a line of text to our listbox. """ self.walker.append(urwid.Text(text)) self.walker.set_focus(len(self.walker.contents)) def update_screen(self, size): canvas = self.frame.render(size, focus=True) self.draw_screen(size, canvas)