Beispiel #1
0
    def create(self,  configPath, userPath,  command):
        self._configPath = configPath
        self._userPath = userPath
        self._command = command
        if not os.path.exists(self._configPath):
            _log = Log()
            _log.create("",  False,  True, LogLevel.Debug , LogLevel.Debug, LogLevel.Debug)
            _log.write(LogLevel.Error,  "Cannot Find a path to the configuration files at {0}. Exiting...".format(self._configPath))
            exit(1)
        # Add the default options
        self.AddOptionString("ConfigPath", configPath, False)	# Path to the OpenZWave config folder.
        self.AddOptionString("UserPath",userPath, False)	# Path to the user's data folder.

        self.AddOptionBool("Logging",True)						# Enable logging of library activity.
        self.AddOptionString("LogFileName","OZWEmul_Log.txt",False)	# Name of the log file (can be changed via Log::SetLogFileName)
        self.AddOptionBool("AppendLogFile",False)					# Append new session logs to existing log file (False = overwrite)
        self.AddOptionBool("ConsoleOutput",True)						# Display log information on console (as well as save to disk)
        self.AddOptionInt("SaveLogLevel", LogLevel.Detail)			# Save (to file) log messages equal to or above Detail
        self.AddOptionInt("QueueLogLevel", LogLevel.Debug)			# Save (in RAM) log messages equal to or above Debug
        self.AddOptionInt("DumpTriggerLevel", LogLevel.Never)			# Default is to never dump RAM-stored log messages

        self.AddOptionBool("Associate",True)						# Enable automatic association of the controller with group one of every device.
        self.AddOptionString("Exclude","",	True)		# Remove support for the listed command classes.
        self.AddOptionString("Include","",True)		# Only handle the specified command classes.  The Exclude option is ignored if anything is listed here.
        self.AddOptionBool("NotifyTransactions",False)					# Notifications when transaction complete is reported.
        self.AddOptionString("Interface","",True)		# Identify the serial port to be accessed (TODO: change the code so more than one serial port can be specified and HID)
        self.AddOptionBool("SaveConfiguration",True)						# Save the XML configuration upon driver close.
        self.AddOptionInt("DriverMaxAttempts",0)

        self.AddOptionInt("PollInterval",30000)						# 30 seconds (can easily poll 30 values in this time; ~120 values is the effective limit for 30 seconds)
        self.AddOptionBool("IntervalBetweenPolls",False)					# if False, try to execute the entire poll list within the PollInterval time frame
                                                                                          # if True, wait for PollInterval milliseconds between polls
        self.AddOptionBool("SuppressValueRefresh",False)					# if True, notifications for refreshed (but unchanged) values will not be sent
        self.AddOptionBool("PerformReturnRoutes",True)					# if true, return routes will be updated
        
        self.AddOptionString("NetworkKey", "", False)
        self.AddOptionBool("RefreshAllUserCodes", False)             # if true, during startup, we refresh all the UserCodes the device reports it supports. If False, we stop after we get the first "Available" slot (Some devices have 250+ usercode slots! - That makes our Session Stage Very Long )
        self.AddOptionInt("RetryTimeout", RETRY_TIMEOUT)       # How long do we wait to timeout messages sent
        self.AddOptionBool("EnableSIS", True)                        # Automatically become a SUC if there is no SUC on the network.
        self.AddOptionBool("AssumeAwake", True)                      # Assume Devices that Support the Wakeup CC are awake when we first query them....
        self.AddOptionBool("NotifyOnDriverUnload", False)       # Should we send the Node/Value Notifications on Driver Unloading - Read comments in Driver::~Driver() method about possible race conditions
Beispiel #2
0
class Manager(object):
    """Manager as singleton, and singleton options link"""

    instance = None
    initialized = False

    def __new__(cls, *args, **kargs):
        cls._log = None
        if OPTIONS is not None and OPTIONS.AreLocked:
            if Manager.instance is None:
                Manager.instance = object.__new__(cls, *args, **kargs)
                Manager.initialized = False
            else:
                Manager.initialized = True
            cls._options = OPTIONS
            return Manager.instance
        cls._log = Log()
        cls._log.create("", False, True, LogLevel.Debug, LogLevel.Debug,
                        LogLevel.Debug)
        cls._log.write(LogLevel.Error, cls,
                       "Options have not been created and locked. Exiting...")
        exit(1)
        return None

    def __init__(self):
        global MANAGER
        if not self.initialized:
            self._nodes = []
            self.drivers = []
            self._DeviceClass = []
            self.zwNetworks = {}
            self.paramsConfig = {}
            self._stop = threading.Event()
            #        find, configPath = self._options.GetOptionAsString( "ConfigPath")
            #        self.readXmlDeviceClasses(configPath)
            #        self.manufacturers = Manufacturers(configPath)
            #        self.cmdClassRegistered = CommandClasses(self)
            MANAGER = self

    def __del__(self):
        global MANAGER
        MANAGER = None
        self.instance = None
        self.initialized = False
        self._stop.set()

    def Create(self):
        # Create the log file (if enabled)
        find, logging = self._options.GetOptionAsBool("Logging")
        if not find: logging = False
        find, userPath = self._options.GetOptionAsString("UserPath")
        if not find: userPath = ""
        find, logFileNameBase = self._options.GetOptionAsString("LogFileName")
        if not find: logFileNameBase = "OZWEmule_Log.txt"
        find, bAppend = self._options.GetOptionAsBool("AppendLogFile")
        if not find: bAppend = False
        find, bConsoleOutput = self._options.GetOptionAsBool("ConsoleOutput")
        if not find: bConsoleOutput = True
        find, nSaveLogLevel = self._options.GetOptionAsInt("SaveLogLevel")
        if not find: nSaveLogLevel = LogLevel.Debug  #LogLevel.Detail
        find, nQueueLogLevel = self._options.GetOptionAsInt("QueueLogLevel")
        if not find: nQueueLogLevel = LogLevel.StreamDetail  # LogLevel.Debug
        find, nDumpTrigger = self._options.GetOptionAsInt("DumpTriggerLevel")
        if not find: nDumpTrigger = LogLevel.Warning
        logFilename = userPath + logFileNameBase
        self._log = Log()
        self._log.create(logFilename, bAppend, bConsoleOutput, nSaveLogLevel,
                         nQueueLogLevel, nDumpTrigger)
        self._log.setLoggingState(logging)
        self._options.setLog(self._log)
        find, configPath = self._options.GetOptionAsString("ConfigPath")
        self.readXmlDeviceClasses(configPath)
        self.manufacturers = Manufacturers(configPath)
        self.cmdClassRegistered = CommandClasses(self)
        self.cmdClassRegistered.RegisterCommandClasses()
        #        try :
        #            self.paramsConfig = readJsonFile('../data/config_emulation.json')
        #            self._log.write(LogLevel.Always, self,"Config parameters loaded : {0}".format(self.paramsConfig))
        #        except:
        #            self._log.write(LogLevel.Warning, self,"No correct file config for emulation in data path.")
        self.loadXmlConfig()
        #        Scene.ReadScenes()
        self._log.write(
            LogLevel.Always, self,
            "OpenZwave-emulator Version {0} Starting Up".format(
                self.getVersionAsString()))
        for homeId in self.zwNetworks:
            self.startDriver(homeId)

    def GetValAsHex(self, value, nChar=2):
        print
        if type(value) != 'list': data = [value]
        else: data = value
        return GetDataAsHex(data, nChar)

    def checkVirtualCom(self, homeId):
        """Check if a virtual port emulator is running"""
        if 'configData' in self.zwNetworks[homeId]:
            configData = self.zwNetworks[homeId]['configData']
            if 'virtualcom' in configData:
                if configData['virtualcom']['modul'] == 'socat':
                    try:
                        pids = psutil.pids()
                        for i in pids:
                            p = psutil.Process(i)
                            if p.name() == 'socat':
                                chk_zwavectrl = False
                                chk_emulator = False
                                for lig in p.cmdline():
                                    if lig.find(configData['virtualcom']
                                                ['ports']['zwavectrl']) != -1:
                                        chk_zwavectrl = True
                                    if lig.find(configData['virtualcom']
                                                ['ports']['emulator']) != -1:
                                        chk_emulator = True
                                if chk_zwavectrl and chk_emulator:
                                    self._log.write(
                                        LogLevel.Always, self,
                                        "Virtual port socat running on {0} for zwave serial port {1}."
                                        .format(
                                            configData['virtualcom']['ports']
                                            ['emulator'],
                                            configData['virtualcom']['ports']
                                            ['zwavectrl']))
                                return True
                    except Exception as e:
                        self._log.write(LogLevel.Warning, self,
                                        "Socat Process error : {0}".format(e))
        self._log.write(LogLevel.Always, self,
                        "Virtual communication system not running.")
        return False

    def startVirtualCom(self, homeId, start=False):
        if 'configData' in self.zwNetworks[
                homeId] and 'virtualcom' in self.zwNetworks[homeId][
                    'configData']:
            virtualcom = self.zwNetworks[homeId]['configData']['virtualcom']
            if start or virtualcom['start'] == 'auto':
                if not self.checkVirtualCom(homeId):
                    if virtualcom['modul'] == 'socat':
                        if virtualcom['ports']['zwavectrl'] and virtualcom[
                                'ports']['emulator']:
                            self._log.write(
                                LogLevel.Info, self,
                                "Starting Virtual communication system...")
                            subprocess.Popen([
                                'socat', '-d', '-d',
                                'PTY,ignoreeof,echo=0,raw,link={0}'.format(
                                    virtualcom['ports']['zwavectrl']),
                                'PTY,ignoreeof,echo=0,raw,link={0}'.format(
                                    virtualcom['ports']['emulator'])
                            ])
                            self._stop.wait(1)
                            if not self.checkVirtualCom(homeId):
                                self._log.write(
                                    LogLevel.Error, self,
                                    "Error on starting Virtual communication system."
                                )
                    else:
                        self._log.write(
                            LogLevel.Warning, self,
                            "Virtual communication configuration not handled : {0}"
                            .format(virtualcom))
            else:
                self._log.write(
                    LogLevel.Always, self,
                    "Virtual communication system not in auto start-up.")
        else:
            self._log.write(
                LogLevel.Warning, self,
                "No configuration set for virtual communication on zwave HomeId {0}"
                .format(homeId))

    def getVersionAsString(self):
        return "{0}.{1}.{2}".format(ozw_vers_major, ozw_vers_minor,
                                    ozw_vers_revision)

    def readXmlNetwork(self, fileConf):
        return networkFileConfig(fileConf)

    def readXmlDeviceClasses(self, pathConf):
        self._DeviceClass = DeviceClasses(pathConf)

    def loadXmlConfig(self):
        dataDir = '../data'
        files = os.listdir(dataDir)
        xmlFormat = r"^zwcfg_0x[0-9,a-f,A-F]{8}.xml$"
        for f in files:
            if re.match(xmlFormat, f) is not None:
                if f not in self.zwNetworks:
                    self._log.write(
                        LogLevel.Always, self,
                        "Find and loading {0} openzwave file config....".
                        format(dataDir + "/" + f))
                    xmlData = self.readXmlNetwork(dataDir + "/" + f)
                    driverData = xmlData.getDriver(0)
                    homeId = driverData['homeId']
                    self.zwNetworks[homeId] = {'xmlData': xmlData}
                    configFile = f.replace('xml', 'json')
                    try:
                        self.zwNetworks[homeId]['configData'] = readJsonFile(
                            dataDir + "/" + configFile)
                        self._log.write(
                            LogLevel.Always, self,
                            "Config for emulation loaded : {0}".format(
                                self.zwNetworks[homeId]['configData']))
                    except:
                        self._log.write(
                            LogLevel.Error, self,
                            "Error on readind config file for emulation :{0}".
                            format(dataDir + "/" + configFile))
                    print driverData
                    nodes = self.zwNetworks[homeId]['xmlData'].listeNodes()
                    for node in nodes:
                        xmlNode = self.zwNetworks[homeId]['xmlData'].getNode(
                            node)
                        self.addXmlNode(homeId, xmlNode['id'], xmlNode)
                    self.startVirtualCom(homeId)
                    self.drivers.append(
                        Driver(self, self.getNode(homeId,
                                                  driverData['nodeId']),
                               driverData))
                    print " +++ driver added +++"
                else:
                    self._log.write(
                        LogLevel.Warning, self,
                        "Zwave network allready loaded :{0}".format(f))

    def resetZwNetwork(self, oldHomeId, newHomeId):
        ctrl = self.GetDriver(oldHomeId)
        self.zwNetworks[newHomeId] = self.zwNetworks.pop(oldHomeId)
        self.zwNetworks[newHomeId]['configData']['controller'][
            'fakeneighbors'] = {}
        nodes = []
        for node in self.zwNetworks[newHomeId]['configData']['nodes']:
            if node['nodeid'] == ctrl._node.nodeId:
                nodes = [node]
                break
        self.zwNetworks[newHomeId]['configData']['nodes'] = nodes

    def getZwVersion(self, homeId):
        if homeId:
            if 'controller' in self.zwNetworks[homeId]['configData']:
                if 'zwversion' in self.zwNetworks[homeId]['configData'][
                        'controller']:
                    return self.zwNetworks[homeId]['configData']['controller'][
                        'zwversion']
            return ZWVERSION
        return ""

    def getSerialAPIVersion(self, homeId):
        if homeId:
            if 'controller' in self.zwNetworks[homeId]['configData']:
                if 'serialapiversion' in self.zwNetworks[homeId]['configData'][
                        'controller']:
                    return self.zwNetworks[homeId]['configData']['controller'][
                        'serialapiversion']
            return SERIALAPIVERSION
        return ""

    def getRFChipVersion(self, homeId):
        if homeId:
            if 'controller' in self.zwNetworks[homeId]['configData']:
                if 'rfchipversion' in self.zwNetworks[homeId]['configData'][
                        'controller']:
                    return self.zwNetworks[homeId]['configData']['controller'][
                        'rfchipversion']
            return RFCHIPVERSION
        return ""

    def getFakeNeighbors(self, homeId, nodeId):
        if homeId:
            if 'controller' in self.zwNetworks[homeId]['configData']:
                if 'fakeneighbors' in self.zwNetworks[homeId]['configData'][
                        'controller']:
                    if str(nodeId) in self.zwNetworks[homeId]['configData'][
                            'controller']['fakeneighbors']:
                        return self.zwNetworks[homeId]['configData'][
                            'controller']['fakeneighbors'][str(nodeId)]
            return []
        return []

    def getEmulNodeData(self, homeId, nodeId):
        if homeId:
            if 'nodes' in self.zwNetworks[homeId]['configData']:
                for n in self.zwNetworks[homeId]['configData']['nodes']:
                    if 'nodeid' in n and n['nodeid'] == nodeId:
                        return n
        return {
            "nodeid": nodeId,
            "comment": "Auto comment",
            "failed": False,
            "timeoutwakeup": 0,
            "wakeupduration": 0,
            "pollingvalues": [],
            "cmdclssextraparams": {}
        }

    def matchHomeID(self, homeId):
        """Evalue si c'est bien un homeID, retourne le homeID ou None"""
        if type(homeId) in [long, int]:
            return "0x%0.8x" % homeId
        homeIDFormat = r"^0x[0-9,a-f]{8}$"
        if re.match(homeIDFormat, homeId.lower()) is not None:
            return homeId.lower()
        return None

    def addXmlNode(self, homeId, nodeId, xmlNode):
        for n in self._nodes:
            if n.homeId == homeId and n.nodeId == nodeId:
                self._log.write(
                    LogLevel.Warning, self,
                    "Node {0} on homeId {1} from xml config file allready exist, abording add."
                    .format(nodeId, homeId))
                return None
        node = Node(self, homeId, nodeId, xmlNode)
        self._nodes.append(node)
        self._log.write(
            LogLevel.Info, self,
            "Node {0} on homeId {1} added from xml config file.".format(
                nodeId, homeId))

    def GetCommandClassId(self, cmdClass):
        return self.cmdClassRegistered.GetCommandClassId(cmdClass)

    def getNode(self, homeId, nodeId):
        for n in self._nodes:
            if (n.homeId == homeId or self.matchHomeID(n.homeId)
                    == homeId) and n.nodeId == nodeId:
                return n
        return None

    def getNodesOfhomeId(self, homeId):
        """Return all nodes from zwave network"""
        retval = []
        for n in self._nodes:
            if (n.homeId == homeId or self.matchHomeID(n.homeId) == homeId):
                retval.append(n)
        return retval

    def getListNodeId(self, homeId):
        listN = []
        for n in self._nodes:
            if n.homeId == homeId:
                listN.append(n.nodeId)
        return listN

    def copyNode(self, node):
        """Copy a node object add it on manager list nodes and set it not include.
           Return the new node object.
        """
        #        newNode = copy.copy(node)
        #        newNode.homeId = 0
        nodeId = self.getFirstFreeNodeIdBeforeInclude()
        newNode = Node(self, 0, nodeId, node.GetXmlData)
        newNode.ClearAddingNode()
        newNode.Reset()
        self._nodes.append(newNode)
        self._log.write(
            LogLevel.Info, self,
            "Manager create new node by copy node {0}.{1}.".format(
                node.homeId, node.nodeId))
        return newNode

    def getFirstFreeNodeIdBeforeInclude(self):
        """"Return the fisrt nodeId free to add node in manager list """
        listId = []
        for n in self._nodes:
            if n.homeId == 0:
                listId.append(n.nodeId)
        for id in range(1, 255):
            if id not in listId:
                break
        return id

    def includeNewNode(self, homeId, node):
        """Include a new node in zwave network"""
        ctrl = self.GetDriver(homeId)
        return ctrl.includeNode(node)

    def resetHomeId(self, oldHomeId, newHomeId):
        for n in self._nodes:
            if (n.homeId == oldHomeId
                    or self.matchHomeID(n.homeId) == oldHomeId):
                n.homeId = newHomeId

    def startDriver(self, homeId):
        if self.checkVirtualCom(homeId):
            serialport = self.zwNetworks[homeId]['configData']['virtualcom'][
                'ports']['emulator']
            if self.drivers:
                for driver in self.drivers:
                    if driver.serialport is None:  # Object Driver not assigned and ready to set serialport
                        driver.setSerialport(serialport)
                        self._log.write(
                            LogLevel.Info, self,
                            "Added driver for controller {0}".format(
                                serialport))
                        driver.Start()
                        return True
                    elif driver.serialport == serialport:
                        self._log.write(
                            LogLevel.Warning, self,
                            "Cannot add driver for controller {0} - driver already exists"
                            .format(serialport))
                        break
                self._log.write(
                    LogLevel.Warning, self,
                    "Cannot add driver for controller {0} - no emulate driver available"
                    .format(serialport))
            else:
                self._log.write(
                    LogLevel.Info, Warning,
                    "Cannot add driver for controller {0} - no emulate driver loaded"
                    .format(serialport))
        return False

    def GetDriver(self, homeId):
        for driver in self.drivers:
            if homeId == driver.homeId: return driver
        return None

    def IsSupportedCommandClasses(self, clsId):
        return self.cmdClassRegistered.IsSupported(clsId)

    def SetProductDetails(self, node, manufacturerId, productType, productId):
        manufacturerName = "Unknown: id=%.4x" % manufacturerId
        productName = "Unknown: type=%.4x, id=%.4x" % (productType, productId)
        configPath = ""
        # Try to get the real manufacturer and product names
        manufacturer = self.manufacturers.getManufacturer(manufacturerId)
        if manufacturer:
            # Replace the id with the real name
            manufacturerName = manufacturer['name']
            # Get the product
            for p in manufacturer['products']:
                if (int(productId, 16) == int(p['id'], 16)) and (int(
                        productType, 16) == int(p['type'], 16)):
                    productName = p['name']
                    configPath = p['config'] if 'config' in p else ""
        # Set the values into the node
        # Only set the manufacturer and product name if they are
        # empty - we don't want to overwrite any user defined names.
        if node.GetManufacturerName == "":
            node.SetManufacturerName(manufacturerName)
        if node.GetProductName == "":
            node.SetProductName(productName)
        node.SetManufacturerId("%.4x" % manufacturerId)
        node.SetProductType("%.4x" % productType)
        node.SetProductId("%.4x" % productId)
        return configPath