Example #1
0
    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()
Example #2
0
    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)
Example #3
0
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)
        
Example #4
0
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
Example #5
0
    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))
Example #6
0
    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
        }
Example #7
0
    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
Example #8
0
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
Example #10
0
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
Example #11
0
    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
        }
Example #12
0
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
Example #13
0
    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
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
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
Example #17
0
    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")
Example #19
0
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)
Example #20
0
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
Example #21
0
def main():

    term = Terminal()

    options = ZWaveOption(device='/dev/ttyACM0')
    options.set_log_file('test.log')
    options.set_append_log_file(True)
    options.set_console_output(False)
    options.set_logging(True)
    options.lock()

    network = ZWaveNetwork(options)
    event_handler = EventHandler()

    start_time = dt.utcnow()

    composer: Composer
    with ComposerContext(term) as composer:

        sb = StatusBuffer(term)
        help_dialog = HelpDialog(term)

        composer.add_widget(sb)
        composer.add_widget(help_dialog.dialog)

        sb.set_buffer_behavior(StatusBuffer.BEHAVIOR_TOP)
        controller = BufferController(sb, network)
        event_handler.register(controller)
        print("> {}".format(controller.handled_buffer_events()))
        sb.set_trigger(controller.handled_buffer_events(),
                       controller.handle_buffer_event)

        starting_spinner = 0
        available_since = None

        last_known_state = None
        while True:
            ch = term.inkey(timeout=0.25)
            if ch:
                composer.handle_inkey(ch)
            controller.update()
            composer.refresh()
            time.sleep(0.25)
    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__(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
Example #24
0
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
Example #25
0
    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()
Example #26
0
    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)
Example #27
0
	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)
Example #28
0
    def __init__(self, device, logging=False):

        options = ZWaveOption(device,
                              config_path="/etc/openzwave",
                              user_path=".", cmd_line="")

        options.set_log_file("OZW_Log.log")
        options.set_append_log_file(False)
        options.set_console_output(False)
        options.set_logging(logging)
        options.lock()

        dispatcher.connect(
            self.on_started, ZWaveNetwork.SIGNAL_NETWORK_STARTED)
        dispatcher.connect(self.on_failed, ZWaveNetwork.SIGNAL_NETWORK_FAILED)
        dispatcher.connect(self.on_ready, ZWaveNetwork.SIGNAL_NETWORK_READY)

        self.state = None
        self.needs_update = False
        self.resources = []

        self.network = ZWaveNetwork(options, autostart=True)

        asyncio.get_event_loop().create_task(self._loop())
    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
        }
Example #30
0
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
Example #31
0
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 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()
Example #33
0
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)
Example #34
0
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()
Example #35
0
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()
Example #36
0
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
Example #37
0
#import openzwave
#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")
Example #38
0
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)
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')
Example #40
0
if six.PY3:
    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 :(.")
Example #41
0
    from openzwave.network import ZWaveNetwork
    from openzwave.option import ZWaveOption
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"
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()
Example #43
0
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
Example #44
0
def list_nodes(args):
    global home_id
    if args.timeout is None:
        args.timeout = 60 * 60 * 4 + 1
    import openzwave
    from openzwave.node import ZWaveNode
    from openzwave.value import ZWaveValue
    from openzwave.scene import ZWaveScene
    from openzwave.controller import ZWaveController
    from openzwave.network import ZWaveNetwork
    from openzwave.option import ZWaveOption

    #Define some manager options
    print(
        "-------------------------------------------------------------------------------"
    )
    print("Define options for device {0}".format(args.device))
    options = ZWaveOption(device=args.device,
                          config_path=args.config_path,
                          user_path=args.user_path)
    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()

    print("Start network")
    network = ZWaveNetwork(options, log=None)

    delta = 0.5
    for i in range(0, int(args.timeout / delta)):
        time.sleep(delta)
        if network.state >= network.STATE_AWAKED:
            break

    print(
        "-------------------------------------------------------------------------------"
    )
    print("Network is awaked. Talk to controller.")
    print("Get python_openzwave version : {}".format(
        network.controller.python_library_version))
    print("Get python_openzwave config version : {}".format(
        network.controller.python_library_config_version))
    print("Get python_openzwave flavor : {}".format(
        network.controller.python_library_flavor))
    print("Get openzwave version : {}".format(
        network.controller.ozw_library_version))
    print("Get config path : {}".format(
        network.controller.library_config_path))
    print("Controller capabilities : {}".format(
        network.controller.capabilities))
    print("Controller node capabilities : {}".format(
        network.controller.node.capabilities))
    print("Nodes in network : {}".format(network.nodes_count))

    print(
        "-------------------------------------------------------------------------------"
    )
    if args.timeout > 1800:
        print(
            "You defined a really long timneout. Please use --help to change this feature."
        )
    print("Wait for network ready ({0}s)".format(args.timeout))
    for i in range(0, int(args.timeout / delta)):
        time.sleep(delta)
        if network.state == network.STATE_READY:
            break
    print(
        "-------------------------------------------------------------------------------"
    )
    if network.state == network.STATE_READY:
        print("Network is ready. Get nodes")
    elif network.state == network.STATE_AWAKED:
        print(
            "Network is awake. Some sleeping devices may miss. You can increase timeout to get them. But will continue."
        )
    else:
        print(
            "Network is still starting. You MUST increase timeout. But will continue."
        )

    for node in network.nodes:

        print("------------------------------------------------------------")
        print("{} - Name : {} ( Location : {} )".format(
            network.nodes[node].node_id, network.nodes[node].name,
            network.nodes[node].location))
        print(" {} - Ready : {} / Awake : {} / Failed : {}".format(
            network.nodes[node].node_id, network.nodes[node].is_ready,
            network.nodes[node].is_awake, network.nodes[node].is_failed))
        print(" {} - Manufacturer : {}  ( id : {} )".format(
            network.nodes[node].node_id, network.nodes[node].manufacturer_name,
            network.nodes[node].manufacturer_id))
        print(
            " {} - Product : {} ( id  : {} / type : {} / Version : {})".format(
                network.nodes[node].node_id, network.nodes[node].product_name,
                network.nodes[node].product_id,
                network.nodes[node].product_type, network.nodes[node].version))
        print(" {} - Command classes : {}".format(
            network.nodes[node].node_id,
            network.nodes[node].command_classes_as_string))
        print(" {} - Capabilities : {}".format(
            network.nodes[node].node_id, network.nodes[node].capabilities))
        print(" {} - Neighbors : {} / Power level : {}".format(
            network.nodes[node].node_id, network.nodes[node].neighbors,
            network.nodes[node].get_power_level()))
        print(" {} - Is sleeping : {} / Can wake-up : {} / Battery level : {}".
              format(network.nodes[node].node_id,
                     network.nodes[node].is_sleeping,
                     network.nodes[node].can_wake_up(),
                     network.nodes[node].get_battery_level()))

    print("------------------------------------------------------------")
    print("Driver statistics : {}".format(network.controller.stats))
    print("------------------------------------------------------------")
    print("Stop network")
    network.stop()
    print("Exit")
Example #45
0
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
Example #46
0
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)