Ejemplo n.º 1
0
    def GetGenmonInitInfo(configfilepath = MyCommon.DefaultConfPath, log = None):

        if configfilepath == None or configfilepath == "":
            configfilepath = MyCommon.DefaultConfPath

        config = MyConfig(configfilepath + "genmon.conf", section = "GenMon", log = log)
        loglocation = config.ReadValue('loglocation', default = ProgramDefaults.LogPath)
        port = config.ReadValue('server_port', return_type = int, default = ProgramDefaults.ServerPort)

        return port, loglocation
Ejemplo n.º 2
0
    def GetGenmonInitInfo(configfilepath = MyCommon.DefaultConfPath, log = None):

        if configfilepath == None or configfilepath == "":
            configfilepath = MyCommon.DefaultConfPath

        config = MyConfig(os.path.join(configfilepath, "genmon.conf"), section = "GenMon", log = log)
        loglocation = config.ReadValue('loglocation', default = ProgramDefaults.LogPath)
        port = config.ReadValue('server_port', return_type = int, default = ProgramDefaults.ServerPort)
        multi_instance = config.ReadValue('multi_instance', return_type = bool, default = False)
        return port, loglocation, multi_instance
Ejemplo n.º 3
0
def GetSiteName():

    try:
        localconfig = MyConfig(filename = ConfigFilePath + 'genmon.conf', section = "GenMon")
        return localconfig.ReadValue('sitename', default = None)
    except Exception as e1:
        log.error("Error in GetSiteName: " + str(e1))
        console.error("Error in GetSiteName: " + str(e1))
        return None
Ejemplo n.º 4
0
        if opt == '-h':
            console.error(HelpStr)
            sys.exit()
        elif opt in ("-a", "--address"):
            address = arg
        elif opt in ("-c", "--configpath"):
            ConfigFilePath = arg
            ConfigFilePath = ConfigFilePath.strip()

    port, loglocation = MySupport.GetGenmonInitInfo(ConfigFilePath, log = console)
    log = SetupLogger("client", loglocation + "genslack.log")

    try:
        config = MyConfig(filename = ConfigFilePath + 'genslack.conf', section = 'genslack', log = log)

        webhook_url = config.ReadValue('webhook_url', default = None)
        channel = config.ReadValue('channel', default = None)
        username = config.ReadValue('username', default = None)
        icon_emoji = config.ReadValue('icon_emoji', default = ":red_circle:")
        title_link = config.ReadValue('title_link', default = None)

        if webhook_url == None or not len(webhook_url):
            log.error("Error: invalid webhoot_url setting")
            console.error("Error: invalid webhoot_url setting")
            sys.exit(2)

        if channel == None or not len(channel):
            log.error("Error: invalid channel setting")
            console.error("Error: invalid channel setting")
            sys.exit(2)
Ejemplo n.º 5
0
        MyClientInterface = ClientInterface(host = address, port = port, log = log)

        config = MyConfig(filename =  os.path.join(ConfigFilePath, 'gengpio.conf'), section = 'gengpio', log = log)
        #setup GPIO using Board numbering
        GPIO.setmode(GPIO.BOARD)

        console.info( GPIO.RPI_INFO)

        GPIO.setwarnings(False)

        TimeUpdated = datetime.datetime(2000, 1, 1, 1, 00)

        # These are the GPIP pins numbers on the Raspberry PI GPIO header
        # https://www.element14.com/community/servlet/JiveServlet/previewBody/73950-102-10-339300/pi3_gpio.png
        # Commnet out or Uncomment the GPIO and Generator status and alarms you wish to monitor.  Limited on GPIO.
        STATUS_READY = config.ReadValue('STATUS_READY', return_type = int, default = 16)
        STATUS_ALARM = config.ReadValue('STATUS_ALARM', return_type = int, default = 18)
        STATUS_SERVICE = config.ReadValue('STATUS_SERVICE', return_type = int, default = 22)
        STATUS_RUNNING = config.ReadValue('STATUS_RUNNING', return_type = int, default = 26)
        STATUS_EXERCISING = config.ReadValue('STATUS_EXERCISING', return_type = int, default = 24)
        STATUS_OFF = config.ReadValue('STATUS_OFF', return_type = int, default = 21)

        # Set additional GPIO based on these error codes
        ER_GENMON = config.ReadValue('ER_GENMON', return_type = int, default = 3)
        ER_INTERNET = config.ReadValue('ER_INTERNET', return_type = int, default = 5)
        ER_SPEED = config.ReadValue('ER_SPEED', return_type = int, default = 29)
        ER_LOW_OIL = config.ReadValue('ER_LOW_OIL', return_type = int, default = 31)
        ER_HIGH_TEMP = config.ReadValue('ER_HIGH_TEMP', return_type = int, default = 33)
        ER_RPM_SENSE = config.ReadValue('ER_RPM_SENSE', return_type = int, default = 35)
        ER_VOLTAGE = config.ReadValue('ER_VOLTAGE', return_type = int, default = 37)
        ER_OVERCRANK = config.ReadValue('ER_OVERCRANK', return_type = int, default = 40)
Ejemplo n.º 6
0
class Loader(MySupport):
    def __init__(self,
                 start=False,
                 stop=False,
                 hardstop=False,
                 loglocation=ProgramDefaults.LogPath,
                 log=None,
                 localinit=False,
                 ConfigFilePath=ProgramDefaults.ConfPath):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop
        self.PipChecked = False
        self.NewInstall = False
        self.Upgrade = False
        self.version = None

        self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = os.path.join(self.ConfigFilePath,
                                           self.ConfigFileName)

        self.ModulePath = os.path.dirname(os.path.realpath(__file__))
        self.ConfPath = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), "conf")

        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader",
                                   os.path.join(loglocation, "genloader.log"))
        else:
            self.log = log

        self.console = SetupLogger("genloader_console",
                                   log_file="",
                                   stream=True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            if not os.path.isdir(self.ConfigFilePath):
                try:
                    os.mkdir(self.ConfigFilePath)
                except Exception as e1:
                    self.LogInfo("Error creating target config directory: " +
                                 str(e1),
                                 LogLine=True)

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " +
                             self.configfile + " Copying file to " +
                             self.ConfigFilePath + " directory.")
                if not self.CopyConfFile():
                    sys.exit(2)

            self.config = MyConfig(filename=self.configfile,
                                   section="genmon",
                                   log=self.log)

            if not self.GetConfig():
                self.CopyConfFile()
                self.LogInfo("Error validating config. Retrying..")
                self.config = MyConfig(filename=self.configfile,
                                       section="genmon",
                                       log=self.log)
                if not self.GetConfig():
                    self.LogInfo(
                        "Error reading config file, 2nd attempt (1), Exiting")
                    sys.exit(2)

            if not self.ValidateConfig():
                self.CopyConfFile()
                self.LogInfo("Error validating config. Retrying..")
                self.config = MyConfig(filename=self.configfile,
                                       section="genmon",
                                       log=self.log)
                if not self.GetConfig():
                    self.LogInfo(
                        "Error reading config file, 2nd attempt (2), Exiting")
                    sys.exit(2)
                if not self.ValidateConfig():
                    self.LogInfo("Error validating config file, Exiting")
                    sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CopyConfFile(self):

        if os.path.isfile(os.path.join(self.ConfPath, self.ConfigFileName)):
            copyfile(os.path.join(self.ConfPath, self.ConfigFileName),
                     self.configfile)
            return True
        else:
            self.LogInfo("Unable to find config file.")
            return False
            sys.exit(2)

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name, required version]
            ['flask', 'flask', None],  # Web server
            # we will not use the check for configparser as this look like it is in backports on 2.7
            # and our myconfig modules uses the default so this generates an error that is not warranted
            #['configparser','configparser',None],   # reading config files
            ['serial', 'pyserial', None],  # Serial
            ['crcmod', 'crcmod', None],  # Modbus CRC
            ['pyowm', 'pyowm', '2.10.0'],  # Open Weather API
            ['pytz', 'pytz', None],  # Time zone support
            ['pysnmp', 'pysnmp', None],  # SNMP
            ['ldap3', 'ldap3', None],  # LDAP
            ['smbus', 'smbus', None],  # SMBus reading of temp sensors
            ['pyotp', 'pyotp', '2.3.0'],  # 2FA support
            ['psutil', 'psutil', None],  # process utilities
            ['chump', 'chump', None],  # for genpushover
            ['twilio', 'twilio', None],  # for gensms
            ['paho.mqtt.client', 'paho-mqtt', None],  # for genmqtt
            ['OpenSSL', 'pyopenssl', None],  # SSL
            ['spidev', 'spidev', None]  # spidev
        ]
        try:
            ErrorOccured = False

            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] +
                                 " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1], version=Module[2]):
                        self.LogInfo("Error: unable to install library " +
                                     Module[1])
                        ErrorOccured = True
                    if Module[0] == "ldap3":
                        # This will correct and issue with the ldap3 modbule not being recogonized in LibrayIsInstalled
                        self.InstallLibrary("pyasn1", update=True)

            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def CheckBaseSoftware(self):

        try:
            if self.PipChecked:
                return True

            if sys.version_info[0] < 3:
                pipProgram = "pip2"
            else:
                pipProgram = "pip3"

            install_list = [pipProgram, '-V']
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in CheckBaseSoftware  : " + str(_error))
            rc = process.returncode

            self.PipChecked = True
            return True
        except Exception as e1:
            self.LogInfo("Error in CheckBaseSoftware: " + str(e1),
                         LogLine=True)
            self.InstallBaseSoftware()
            return False

    #---------------------------------------------------------------------------
    def InstallBaseSoftware(self):

        try:
            if sys.version_info[0] < 3:
                pipProgram = "python-pip"
            else:
                pipProgram = "python3-pip"

            self.LogInfo("Installing " + pipProgram)

            install_list = ["sudo", "apt-get", "-yqq", "update"]
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallBaseSoftware  : " + str(_error))
            rc = process.returncode

            install_list = ["sudo", "apt-get", "-yqq", "install", pipProgram]
            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()
            return True
        except Exception as e1:
            self.LogInfo("Error in InstallBaseSoftware: " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    @staticmethod
    def OneTimeMaint(ConfigFilePath, log):

        FileList = {
            "feedback.json": os.path.dirname(os.path.realpath(__file__)) + "/",
            "outage.txt": os.path.dirname(os.path.realpath(__file__)) + "/",
            "kwlog.txt": os.path.dirname(os.path.realpath(__file__)) + "/",
            "maintlog.json": os.path.dirname(os.path.realpath(__file__)) + "/",
            "Feedback_dat":
            os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
            "Message_dat":
            os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
            'genmon.conf': "/etc/",
            'genserv.conf': "/etc/",
            'gengpio.conf': "/etc/",
            'gengpioin.conf': "/etc/",
            'genlog.conf': "/etc/",
            'gensms.conf': "/etc/",
            'gensms_modem.conf': "/etc/",
            'genpushover.conf': "/etc/",
            'gensyslog.conf': "/etc/",
            'genmqtt.conf': "/etc/",
            'genslack.conf': "/etc/",
            'genexercise.conf': "/etc/",
            'genemail2sms.conf': "/etc/",
            'genloader.conf': "/etc/",
            'mymail.conf': "/etc/",
            'mymodem.conf': "/etc/"
        }
        try:
            # Check to see if we have done this already by checking files in the genmon source directory
            if (not os.path.isfile(
                    os.path.dirname(os.path.realpath(__file__)) +
                    "/genmonlib/Message_dat") and not os.path.isfile(
                        os.path.dirname(os.path.realpath(__file__)) +
                        "/maintlog.json") and not os.path.isfile(
                            os.path.dirname(os.path.realpath(__file__)) +
                            "/outage.txt") and not os.path.isfile(
                                os.path.dirname(os.path.realpath(__file__)) +
                                "/kwlog.txt")
                    and not os.path.isfile("/etc/genmon.conf")):
                return False
            # validate target directory
            if not os.path.isdir(ConfigFilePath):
                try:
                    os.mkdir(ConfigFilePath)
                    if not os.access(ConfigFilePath + File, os.R_OK):
                        pass
                except Exception as e1:
                    log.error("Error validating target directory: " + str(e1),
                              LogLine=True)

            # move files
            for File, Path in FileList.items():
                try:
                    SourceFile = Path + File
                    if os.path.isfile(SourceFile):
                        log.error("Moving " + SourceFile + " to " +
                                  ConfigFilePath)
                        if not MySupport.CopyFile(SourceFile,
                                                  ConfigFilePath + File,
                                                  move=True,
                                                  log=log):
                            log.error("Error: using alternate move method")
                            move(SourceFile, ConfigFilePath + File)
                        if not os.access(ConfigFilePath + File, os.R_OK):
                            pass
                except Exception as e1:
                    log.error("Error moving " + SourceFile)
        except Exception as e1:
            log.error("Error moving files: " + str(e1), LogLine=True)
        return True

    #---------------------------------------------------------------------------
    def FixPyOWMMaintIssues(self):
        try:
            # check version of pyowm
            import pyowm
            if sys.version_info[0] < 3:
                required_version = "2.9.0"
            else:
                required_version = "2.10.0"

            if not self.LibraryIsInstalled("pyowm"):
                self.LogError(
                    "Error in FixPyOWMMaintIssues: pyowm not installed")
                return False

            installed_version = self.GetLibararyVersion("pyowm")

            if installed_version == None:
                self.LogError(
                    "Error in FixPyOWMMaintIssues: pyowm version not found")
                return None

            if self.VersionTuple(installed_version) <= self.VersionTuple(
                    required_version):
                return True

            self.LogInfo(
                "Found wrong version of pyowm, uninstalling and installing the correct version."
            )

            self.InstallLibrary("pyowm", uninstall=True)

            self.InstallLibrary("pyowm", version=required_version)

            return True
        except Exception as e1:
            self.LogErrorLine("Error in FixPyOWMMaintIssues: " + str(e1))
            return False

    #---------------------------------------------------------------------------
    def GetLibararyVersion(self, libraryname, importonly=False):

        try:

            try:
                import importlib
                my_module = importlib.import_module(libraryname)
                return my_module.__version__
            except:

                if importonly:
                    return None
                # if we get here then the libarary does not support a __version__ attribute
                # lets use pip to get the version
                try:
                    if sys.version_info[0] < 3:
                        pipProgram = "pip2"
                    else:
                        pipProgram = "pip3"

                    # This will check if pip is installed
                    if "linux" in sys.platform:
                        self.CheckBaseSoftware()

                    install_list = [pipProgram, 'freeze', libraryname]

                    process = Popen(install_list, stdout=PIPE, stderr=PIPE)
                    output, _error = process.communicate()

                    if _error:
                        self.LogInfo(
                            "Error in GetLibararyVersion using pip : " +
                            libraryname + ": " + str(_error))
                    rc = process.returncode

                    # process output of pip freeze
                    lines = output.splitlines()

                    for line in lines:
                        line = line.decode("utf-8")
                        line = line.strip()
                        if line.startswith(libraryname):
                            items = line.split('==')
                            if len(items) <= 2:
                                return items[1]
                    return None

                except Exception as e1:
                    self.LogInfo("Error getting version of module: " +
                                 libraryname + ": " + str(e1),
                                 LogLine=True)
                    return None
        except Exception as e1:
            self.LogErrorLine("Error in GetLibararyVersion: " + str(e1))
            return None

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self,
                       libraryname,
                       update=False,
                       version=None,
                       uninstall=False):

        try:
            if sys.version_info[0] < 3:
                pipProgram = "pip2"
            else:
                pipProgram = "pip3"

            if version != None and uninstall == False:
                libraryname = libraryname + "==" + version

            # This will check if pip is installed
            if "linux" in sys.platform:
                self.CheckBaseSoftware()

            if update:
                install_list = [pipProgram, 'install', libraryname, '-U']
            elif uninstall:
                install_list = [pipProgram, 'uninstall', '-y', libraryname]
            else:
                install_list = [pipProgram, 'install', libraryname]

            process = Popen(install_list, stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " +
                             libraryname + " : UnInstall: " + str(uninstall) +
                             ": " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname +
                         " : UnInstall: " + str(uninstall) + ": " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(
                            os.path.join(self.ModulePath,
                                         self.CachedConfig[Module]["module"])):
                        self.LogInfo(
                            "Enable to find file " +
                            os.path.join(self.ModulePath,
                                         self.CachedConfig[Module]["module"]))
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(
                        self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(
                        ",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(
                                os.path.join(self.ConfigFilePath, ConfigFile)):
                            if os.path.isfile(
                                    os.path.join(self.ConfPath, ConfigFile)):
                                self.LogInfo("Copying " + ConfigFile + " to " +
                                             self.ConfigFilePath)
                                copyfile(
                                    os.path.join(self.ConfPath, ConfigFile),
                                    os.path.join(self.ConfigFilePath,
                                                 ConfigFile))
                            else:
                                self.LogInfo(
                                    "Enable to find config file " +
                                    os.path.join(self.ConfPath, ConfigFile))
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False

        try:
            if not self.CachedConfig["genmon"]["enable"]:
                self.LogError(
                    "Warning: Genmon is not enabled, assume corrupt file.")
                ErrorOccured = True
            if not self.CachedConfig["genserv"]["enable"]:
                self.LogError("Warning: Genserv is not enabled")

        except Exception as e1:
            self.LogErrorLine(
                "Error in ValidateConfig, possible corrupt file. " + str(e1))
            ErrorOccured = True
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self,
                 section=None,
                 module=None,
                 conffile="",
                 args="",
                 priority='2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section=section)
            self.config.WriteValue('enable', 'False', section=section)
            self.config.WriteValue('hardstop', 'False', section=section)
            self.config.WriteValue('conffile', conffile, section=section)
            self.config.WriteValue('args', args, section=section)
            self.config.WriteValue('priority', priority, section=section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine=True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpioin.conf",
                                       section="gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpioin.conf",
                                           section="gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

            self.config.SetSection("gengpio")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpio.conf",
                                       section="gengpio")
                self.LogError("Updated entry gengpio.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpio.conf",
                                           section="gengpio")
                    self.LogError("Updated entry gengpio.conf")

            # check version info
            self.config.SetSection("genloader")
            self.version = self.config.ReadValue("version", default="0.0.0")
            if self.version == "0.0.0" or not len(self.version):
                self.version = "0.0.0"
                self.NewInstall = True

            if self.VersionTuple(self.version) < self.VersionTuple(
                    ProgramDefaults.GENMON_VERSION):
                self.Upgrade = True

            if self.NewInstall or self.Upgrade:
                self.config.WriteValue("version",
                                       ProgramDefaults.GENMON_VERSION,
                                       section='genloader')
            if self.NewInstall:
                self.LogInfo("Running one time maintenance check")
                self.FixPyOWMMaintIssues()

            # TODO other version checks can be added here

            self.version = ProgramDefaults.GENMON_VERSION

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine=True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = [
                'genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog',
                'gensms', 'gensms_modem', 'genpushover', 'gensyslog',
                'genmqtt', 'genslack', 'genexercise', 'genemail2sms',
                'gentankutil', 'gentankdiy', 'genalexa', 'gensnmp', 'gentemp',
                'gengpioledblink', 'gencthat', 'genloader'
            ]
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genmon' or entry == 'genserv':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , file corruption. ")
                        return False
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genslack.py',
                                      conffile='genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genexercise.py',
                                      conffile='genexercise.conf')
                    if entry == 'genemail2sms':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genemail2sms.py',
                                      conffile='genemail2sms.conf')
                    if entry == 'gentankutil':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentankutil.py',
                                      conffile='gentankutil.conf')
                    if entry == 'genalexa':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genalexa.py',
                                      conffile='genalexa.conf')
                    if entry == 'gensnmp':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gensnmp.py',
                                      conffile='gensnmp.conf')
                    if entry == 'gentemp':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentemp.py',
                                      conffile='gentemp.conf')
                    if entry == 'gentankdiy':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gentankdiy.py',
                                      conffile='gentankdiy.conf')
                    if entry == 'gengpioledblink':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gengpioledblink.py',
                                      conffile='gengpioledblink.conf')
                    if entry == 'gencthat':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='gencthat.py',
                                      conffile='gencthat.conf')
                    if entry == 'genloader':
                        self.LogError("Adding entry: " + entry)
                        self.config.WriteSection(entry)
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                if SectionName == 'genloader':
                    continue
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting module in section " +
                        str(SectionName))
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue(
                        'enable', return_type=bool)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting enable in section " +
                        str(SectionName))
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue(
                        'hardstop', return_type=bool)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting hardstop in section " +
                        str(SectionName))
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting confile in section " +
                        str(SectionName))
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    self.LogError(
                        "Error in GetConfig: expcting args in section " +
                        str(SectionName))
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue(
                        'priority', return_type=int, default=None)
                else:
                    self.LogError(
                        "Error in GetConfig: expcting priority in section " +
                        str(SectionName))
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue(
                        'postloaddelay', return_type=int, default=0)
                else:
                    TempDict['postloaddelay'] = 0

                if self.config.HasOption('pid'):
                    TempDict['pid'] = self.config.ReadValue('pid',
                                                            return_type=int,
                                                            default=0,
                                                            NoLog=True)
                else:
                    TempDict['pid'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine=True)
            return False
        return True

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default=None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module][
                            "priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " +
                                 str(e1),
                                 LogLine=True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(),
                                     key=lambda kv: (-kv[1], kv[0])):
                #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine=True)

        return LoadOrder

    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(
                        self.ModulePath,
                        self.CachedConfig[Module]["module"],
                        pid=self.CachedConfig[Module]["pid"],
                        HardStop=self.CachedConfig[Module]["hardstop"],
                        UsePID=True):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not multi_instance:
                        # check that module is not loaded already, if it is then force it (hard) to unload
                        attempts = 0
                        while True:
                            if MySupport.IsRunning(
                                    prog_name=self.CachedConfig[Module]
                                ["module"],
                                    log=self.log,
                                    multi_instance=multi_instance):
                                # if loaded then kill it
                                if attempts >= 4:
                                    # kill it
                                    if not self.UnloadModule(
                                            self.ModulePath,
                                            self.CachedConfig[Module]
                                        ["module"],
                                            pid=None,
                                            HardStop=True,
                                            UsePID=False):
                                        self.LogInfo("Error killing " +
                                                     self.CachedConfig[Module]
                                                     ["module"])
                                else:
                                    attempts += 1
                                    time.sleep(1)
                            else:
                                break

                    if not self.LoadModule(
                            self.ModulePath,
                            self.CachedConfig[Module]["module"],
                            args=self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module][
                            "postloaddelay"] == None and self.CachedConfig[
                                Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, path, modulename, args=None):
        try:
            try:
                import os
                fullmodulename = os.path.join(path, modulename)
            except Exception as e1:
                fullmodulename = path + "/" + modulename

            if args != None:
                self.LogConsole("Starting " + fullmodulename + " " + args)
            else:
                self.LogConsole("Starting " + fullmodulename)
            try:
                from subprocess import DEVNULL  # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE

            executelist = [sys.executable, fullmodulename]
            if args != None:
                executelist.extend(args.split(" "))
            # This will make all the programs use the same config files
            executelist.extend(["-c", self.ConfigFilePath])
            # close_fds=True
            pid = subprocess.Popen(executelist,
                                   stdout=OutputStream,
                                   stderr=OutputStream,
                                   stdin=OutputStream)
            return self.UpdatePID(modulename, pid.pid)

        except Exception as e1:
            self.LogInfo("Error loading module " + path + ": " + modulename +
                         ": " + str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UnloadModule(self,
                     path,
                     modulename,
                     pid=None,
                     HardStop=False,
                     UsePID=False):
        try:
            LoadInfo = []
            if UsePID:
                if pid == None or pid == "" or pid == 0:
                    return True
                LoadInfo.append("kill")
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append(str(pid))
            else:
                LoadInfo.append('pkill')
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append('-u')
                LoadInfo.append('root')
                LoadInfo.append('-f')
                LoadInfo.append(modulename)

            self.LogConsole("Stopping " + modulename)
            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            return self.UpdatePID(modulename, "")

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UpdatePID(self, modulename, pid=None):

        try:
            filename = os.path.splitext(modulename)[0]  # remove extension
            if not self.config.SetSection(filename):
                self.LogError("Error settting section name in UpdatePID: " +
                              str(filename))
                return False
            self.config.WriteValue("pid", str(pid))
            return True
        except Exception as e1:
            self.LogInfo("Error writing PID for " + modulename + " : " +
                         str(e1))
            return False
        return True
Ejemplo n.º 7
0
#------------------- Command-line interface for gengpioledblink ----------------
if __name__ == '__main__':  # usage program.py [server_address]

    try:
        console, ConfigFilePath, address, port, loglocation, log = MySupport.SetupAddOnProgram(
            "gengpioledblink")
        # Set the signal handler
        signal.signal(signal.SIGINT, signal_handler)

        conf_file = os.path.join(ConfigFilePath, 'gengpioledblink.conf')
        if os.path.isfile(conf_file):
            config = MyConfig(filename=conf_file,
                              section='gengpioledblink',
                              log=log)

            led_pin = config.ReadValue('ledpin', return_type=int, default=12)

        MyClientInterface = ClientInterface(host=address, port=port, log=log)

        #setup GPIO using Board numbering
        GPIO.setmode(GPIO.BOARD)

        console.info(GPIO.RPI_INFO)

        GPIO.setwarnings(False)
        GPIO.setup(led_pin, GPIO.OUT, initial=GPIO.LOW)

        while True:

            # Get Genmon status
            try:
Ejemplo n.º 8
0
class GenTankData(MySupport):

    #------------ GenTankData::init---------------------------------------------
    def __init__(self,
        log = None,
        loglocation = ProgramDefaults.LogPath,
        ConfigFilePath = MyCommon.DefaultConfPath,
        host = ProgramDefaults.LocalHost,
        port = ProgramDefaults.ServerPort,
        console = None):

        super(GenTankData, self).__init__()

        self.LogFileName = os.path.join(loglocation, "gentankutil.log")
        self.AccessLock = threading.Lock()

        self.log = log
        self.console = console

        self.MonitorAddress = host
        self.PollTime =  2
        self.TankID = ""
        self.debug = False
        configfile = os.path.join(ConfigFilePath, 'gentankutil.conf')
        try:
            if not os.path.isfile(configfile):
                self.LogConsole("Missing config file : " + configfile)
                self.LogError("Missing config file : " + configfile)
                sys.exit(1)

            self.config = MyConfig(filename = configfile, section = 'gentankutil', log = self.log)

            self.PollTime = self.config.ReadValue('poll_frequency', return_type = float, default = 60)
            self.debug = self.config.ReadValue('debug', return_type = bool, default = False)
            self.username = self.config.ReadValue('username', default = "")
            self.password = self.config.ReadValue('password', default = "")
            self.tank_name = self.config.ReadValue('tank_name', default = "")

            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine("Error reading " + configfile + ": " + str(e1))
            self.LogConsole("Error reading " + configfile + ": " + str(e1))
            sys.exit(1)

        if self.username == "" or self.username == None or self.password == "" or self.password == None:
            self.LogError("Invalid user name or password, exiting")
            sys.exit(1)

        try:
            self.Generator = ClientInterface(host = self.MonitorAddress, port = port, log = self.log)

            #if not self.CheckGeneratorRequirement():
            #    self.LogError("Requirements not met. Exiting.")
            #    sys.exit(1)

            self.tank = tankutility(self.username, self.password, self.log, debug = self.debug)
            # start thread monitor time for exercise
            self.Threads["TankCheckThread"] = MyThread(self.TankCheckThread, Name = "TankCheckThread", start = False)
            self.Threads["TankCheckThread"].Start()

            signal.signal(signal.SIGTERM, self.SignalClose)
            signal.signal(signal.SIGINT, self.SignalClose)

        except Exception as e1:
            self.LogErrorLine("Error in GenTankData init: " + str(e1))
            self.console.error("Error in GenTankData init: " + str(e1))
            sys.exit(1)

    #----------  GenTankData::SendCommand --------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " + str(Command))
            data = ""

        return data
    #----------  GenTankData::CheckGeneratorRequirement ------------------------
    def CheckGeneratorRequirement(self):

        try:
            data = self.SendCommand("generator: start_info_json")
            StartInfo = {}
            StartInfo = json.loads(data)
            if not "evolution" in StartInfo["Controller"].lower() and not "nexus" in StartInfo["Controller"].lower():
                self.LogError("Error: Only Evolution or Nexus controllers are supported for this feature: " + StartInfo["Controller"])
                return False
            return True
        except Exception as e1:
            self.LogErrorLine("Error in CheckGeneratorRequirement: " + str(e1))
            return False


    # ---------- GenTankData::Login---------------------------------------------
    def Login(self, force = False):

        if force:
            self.TankID = ""
        if len(self.TankID):
            # already logged in
            return True
        if not self.tank.Login():
            return False
        self.TankID = self.tank.GetIDFromName(self.tank_name)
        if not len(self.TankID):
            return False
        return True

    # ---------- GenTankData::TankCheckThread-----------------------------------
    def TankCheckThread(self):

        time.sleep(1)
        LastLoginTime = datetime.datetime.now()
        while True:
            try:
                NUMBER_OF_SECONDS = 60 * 60 * 12    # 12 hours

                if ((datetime.datetime.now() - LastLoginTime).total_seconds() > NUMBER_OF_SECONDS) or not len(self.TankID):
                    self.LogDebug("Login ")
                    if not self.Login(force = True):
                        self.LogError("Error logging in in TankCheckThread, retrying")

                dataforgenmon = {}

                tankdata = self.tank.GetData(self.TankID)
                if tankdata != None:
                    dataforgenmon["Tank Name"] = tankdata["name"]
                    dataforgenmon["Capacity"] = self.tank.GetCapacity()
                    dataforgenmon["Percentage"] = self.tank.GetPercentage()

                    retVal = self.SendCommand("generator: set_tank_data=" + json.dumps(dataforgenmon))
                    self.LogDebug(retVal)
                if self.WaitForExit("TankCheckThread", float(self.PollTime * 60)):
                    return
            except Exception as e1:
                self.LogErrorLine("Error in TankCheckThread: " + str(e1))
                if self.WaitForExit("TankCheckThread", float(self.PollTime * 60)):
                    return

    # ----------GenTankData::SignalClose----------------------------------------
    def SignalClose(self, signum, frame):

        self.Close()
        sys.exit(1)

    # ----------GenTankData::Close----------------------------------------------
    def Close(self):
        self.KillThread("TankCheckThread")
        self.Generator.Close()
Ejemplo n.º 9
0
    try:
        console, ConfigFilePath, address, port, loglocation, log = MySupport.SetupAddOnProgram(
            "genalexa")

        # Set the signal handler
        signal.signal(signal.SIGINT, signal_handler)

        if not os.path.isfile(os.path.join(ConfigFilePath, 'genalexa.conf')):
            console.error("Error: config file not found")
            log.error("Error: config file not found")
            sys.exit(1)
        config = MyConfig(filename=os.path.join(ConfigFilePath,
                                                'genalexa.conf'),
                          section='genalexa',
                          log=log)
        FauxmoName = config.ReadValue('name', default=" generator")
        FauxmoPort = config.ReadValue('port', return_type=int, default=52004)
        Debug = config.ReadValue('debug', return_type=bool, default=False)

        log.error("Key word: " + FauxmoName + "; Port: " + str(FauxmoPort) +
                  "; " + "Debug: " + str(Debug))
        MyClientInterface = ClientInterface(host=address, port=port, log=log)

        data = MyClientInterface.ProcessMonitorCommand(
            "generator: start_info_json")
        StartInfo = {}
        StartInfo = json.loads(data)
        remoteCommands = False
        if 'RemoteCommands' in StartInfo:
            remoteCommands = StartInfo['RemoteCommands']
        if remoteCommands == False:
Ejemplo n.º 10
0
class MyMail(MySupport):
    def __init__(self,
                 monitor=False,
                 incoming_folder=None,
                 processed_folder=None,
                 incoming_callback=None,
                 localinit=False,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath="/etc/",
                 log=None,
                 start=True):

        self.Monitor = monitor  # true if we receive IMAP email
        self.IncomingFolder = incoming_folder  # folder to look for incoming email
        self.ProcessedFolder = processed_folder  # folder to move mail to once processed
        self.IncomingCallback = incoming_callback  # called back with mail subject as a parameter
        if ConfigFilePath == None or ConfigFilePath == "":
            self.ConfigFilePath = "/etc/"
        else:
            self.ConfigFilePath = ConfigFilePath
        self.Mailbox = 0
        self.EmailSendQueue = []  # queue for email to send
        self.DisableEmail = False
        self.DisableIMAP = False
        self.DisableSNMP = False
        self.DisableSmtpAuth = False
        self.SSLEnabled = False
        self.TLSDisable = False
        self.UseBCC = False
        self.ExtendWait = 0
        self.Threads = {}  # Dict of mythread objects
        self.debug = False
        self.ModulePath = os.path.dirname(
            os.path.dirname(os.path.realpath(__file__)))
        # log errors in this module to a file
        if localinit == True:
            self.logfile = "mymail.log"
            self.configfile = "mymail.conf"
        else:
            self.logfile = os.path.join(loglocation, "mymail.log")
            self.configfile = os.path.join(self.ConfigFilePath, "mymail.conf")

        if log == None:
            self.log = SetupLogger("mymail", self.logfile)
        else:
            self.log = log

        # if mymail.conf is present attempt to copy it from the
        # main source directory
        if not os.path.isfile(self.configfile):
            if os.path.join(os.path.isfile(self.ModulePath, "mymail.conf")):
                copyfile(os.path.join(self.ModulePath, "mymail.conf"),
                         self.configfile)
            else:
                self.LogError("Missing config file : " + self.configfile)
                sys.exit(1)

        self.config = MyConfig(filename=self.configfile,
                               section="MyMail",
                               log=self.log)

        self.GetConfig()

        if self.DisableEmail:
            self.DisableIMAP = True
            self.DisableSNMP = True
            self.Monitor = False

        if not len(self.SMTPServer):
            self.DisableSNMP = True

        if not len(self.IMAPServer):
            self.DisableIMAP = True
            self.Monitor = False

        atexit.register(self.Close)

        if not self.DisableEmail:
            if not self.DisableSMTP and self.SMTPServer != "":
                self.Threads["SendMailThread"] = MyThread(
                    self.SendMailThread, Name="SendMailThread", start=start)
            else:
                self.LogError("SMTP disabled")

            if not self.DisableIMAP and self.Monitor and self.IMAPServer != "":  # if True then we will have an IMAP monitor thread
                if incoming_callback and incoming_folder and processed_folder:
                    self.Threads["EmailCommandThread"] = MyThread(
                        self.EmailCommandThread,
                        Name="EmailCommandThread",
                        start=start)
                else:
                    self.FatalError(
                        "ERROR: incoming_callback, incoming_folder and processed_folder are required if receive IMAP is used"
                    )
            else:
                self.LogError("IMAP disabled")

    #---------- MyMail.TestSendSettings ----------------------------------------
    @staticmethod
    def TestSendSettings(smtp_server=None,
                         smtp_port=587,
                         email_account=None,
                         sender_account=None,
                         sender_name=None,
                         recipient=None,
                         password=None,
                         use_ssl=False,
                         tls_disable=False,
                         smtpauth_disable=False):

        if smtp_server == None or not len(smtp_server):
            return "Error: Invalid SMTP server"

        if not isinstance(smtpauth_disable, bool) and (email_account == None or
                                                       not len(email_account)):
            return "Error: Invalid email account"

        if sender_account == None or not len(sender_account):
            sender_account = email_account

        if recipient == None or not len(recipient):
            return "Error: Invalid email recipient"

        if password == None or not len(password):
            password = ""

        if smtp_port == None or not isinstance(smtp_port, int):
            return "Error: Invalid SMTP port"

        if use_ssl == None or not isinstance(use_ssl, bool):
            return "Error: Invalid Use SSL value"

        if tls_disable == None or not isinstance(tls_disable, bool):
            return "Error: Invalid TLS Disable value"
        # update date
        dtstamp = datetime.datetime.now().strftime('%a %d-%b-%Y')
        # update time
        tmstamp = datetime.datetime.now().strftime('%I:%M:%S %p')

        msg = MIMEMultipart()
        if sender_name == None or not len(sender_name):
            msg['From'] = "<" + sender_account + ">"
        else:
            msg['From'] = sender_name + " <" + sender_account + ">"

        try:
            recipientList = recipient.strip().split(",")
            recipientList = map(lambda x: x.strip(), recipientList)
            recipienttemp = ">,<"
            recipienttemp = recipienttemp.join(recipientList)
            recipient = "<" + recipienttemp + ">"
        except Exceptin as e1:
            pass

        msg['To'] = recipient
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = "Genmon Test Email"

        msgstr = '\n' + 'Test email from genmon\n'
        body = '\n' + 'Time: ' + tmstamp + '\n' + 'Date: ' + dtstamp + '\n' + msgstr
        msg.attach(MIMEText(body, 'plain', 'us-ascii'))

        try:
            if use_ssl:
                session = smtplib.SMTP_SSL(smtp_server, smtp_port)
                session.ehlo()
            else:
                session = smtplib.SMTP(smtp_server, smtp_port)
                if not tls_disable:
                    session.starttls()
                session.ehlo
                # this allows support for simple TLS
        except Exception as e1:
            #self.LogErrorLine("Error Test SMTP : SSL:<" + str(use_ssl)  + ">: " + str(e1))
            return "Error Initializing SMTP library: " + str(e1)

        try:
            if password != "" and not smtpauth_disable:
                session.login(str(email_account), str(password))

            if "," in recipient:
                multiple_recipients = recipient.split(",")
                session.sendmail(sender_account, multiple_recipients,
                                 msg.as_string())
            else:
                session.sendmail(sender_account, recipient, msg.as_string())
        except Exception as e1:
            #self.LogErrorLine("Error SMTP sendmail: " + str(e1))
            session.quit()
            return "Error sending email: " + str(e1)

        session.quit()
        return "Success"

    #---------- MyMail.GetConfig -----------------------------------------------
    def GetConfig(self, reload=False):

        try:

            if self.config.HasOption('disableemail'):
                self.DisableEmail = self.config.ReadValue('disableemail',
                                                          return_type=bool)
            else:
                self.DisableEmail = False

            if self.config.HasOption('disablesmtp'):
                self.DisableSMTP = self.config.ReadValue('disablesmtp',
                                                         return_type=bool)
            else:
                self.DisableSMTP = False

            if self.config.HasOption('smtpauth_disable'):
                self.DisableSmtpAuth = self.config.ReadValue(
                    'smtpauth_disable', return_type=bool)
            else:
                self.DisableSmtpAuth = False

            if self.config.HasOption('disableimap'):
                self.DisableIMAP = self.config.ReadValue('disableimap',
                                                         return_type=bool)
            else:
                self.DisableIMAP = False

            if self.config.HasOption('usebcc'):
                self.UseBCC = self.config.ReadValue('usebcc', return_type=bool)

            if self.config.HasOption('extend_wait'):
                self.ExtendWait = self.config.ReadValue('extend_wait',
                                                        return_type=int,
                                                        default=0)

            self.debug = self.config.ReadValue('debug',
                                               return_type=bool,
                                               default=False)

            self.EmailPassword = self.config.ReadValue('email_pw', default="")
            self.EmailPassword = self.EmailPassword.strip()
            self.EmailAccount = self.config.ReadValue('email_account')
            if self.config.HasOption('sender_account'):
                self.SenderAccount = self.config.ReadValue('sender_account')
                self.SenderAccount = self.SenderAccount.strip()
                if not len(self.SenderAccount):
                    self.SenderAccount = self.EmailAccount
            else:
                self.SenderAccount = self.EmailAccount

            self.SenderName = self.config.ReadValue('sender_name',
                                                    default=None)

            # SMTP Recepients
            self.EmailRecipient = self.config.ReadValue('email_recipient')
            self.EmailRecipientByType = {}
            for type in ["outage", "error", "warn", "info"]:
                tempList = []
                for email in self.EmailRecipient.split(','):
                    if self.config.HasOption(email):
                        if type in self.config.ReadValue(email).split(','):
                            tempList.append(email)
                    else:
                        tempList.append(email)

                self.EmailRecipientByType[type] = ",".join(tempList)
            # SMTP Server
            if self.config.HasOption('smtp_server'):
                self.SMTPServer = self.config.ReadValue('smtp_server')
                self.SMTPServer = self.SMTPServer.strip()
            else:
                self.SMTPServer = ""
            # IMAP Server
            if self.config.HasOption('imap_server'):
                self.IMAPServer = self.config.ReadValue('imap_server')
                self.IMAPServer = self.IMAPServer.strip()
            else:
                self.IMAPServer = ""
            self.SMTPPort = self.config.ReadValue('smtp_port', return_type=int)

            if self.config.HasOption('ssl_enabled'):
                self.SSLEnabled = self.config.ReadValue('ssl_enabled',
                                                        return_type=bool)

            self.TLSDisable = self.config.ReadValue('tls_disable',
                                                    return_type=bool,
                                                    default=False)

        except Exception as e1:
            self.LogErrorLine("ERROR: Unable to read config file : " + str(e1))
            sys.exit(1)

        return True

    #---------- MyMail.Close ---------------------------------------------------
    def Close(self):
        try:
            if not self.DisableEmail:
                if self.SMTPServer != "" and not self.DisableSMTP:
                    try:
                        self.Threads["SendMailThread"].Stop()
                    except:
                        pass

            if not self.DisableEmail:
                if self.Monitor and self.IMAPServer != "" and not self.DisableIMAP:
                    if self.IncomingCallback != None and self.IncomingFolder != None and self.ProcessedFolder != None:
                        try:
                            self.Threads["EmailCommandThread"].Stop()
                        except:
                            pass

            if self.Monitor:
                if self.Mailbox:
                    try:
                        self.Mailbox.close()
                        self.Mailbox.logout()
                    except:
                        pass
        except Exception as e1:
            self.LogErrorLine("Error Closing Mail: " + str(e1))

    #---------- MyMail.EmailCommandThread --------------------------------------
    def EmailCommandThread(self):

        while True:
            # start email command thread
            try:
                self.Mailbox = imaplib.IMAP4_SSL(self.IMAPServer)
                if self.debug:
                    self.Mailbox.Debug = 4
            except Exception:
                self.LogError("No Internet Connection! ")
                if self.WaitForExit("EmailCommandThread", 120):
                    return  # exit thread
                continue
            try:
                if not self.DisableSmtpAuth:
                    data = self.Mailbox.login(self.EmailAccount,
                                              self.EmailPassword)
            except Exception:
                self.LogError("LOGIN FAILED!!! ")
                if self.WaitForExit("EmailCommandThread", 60):
                    return  # exit thread
                continue
            while True:
                try:
                    rv, data = self.Mailbox.select(self.IncomingFolder)
                    if rv != 'OK':
                        self.LogError("Error selecting mail folder! (select)")
                        if self.WaitForExit("EmailCommandThread", 15):
                            return
                        continue
                    rv, data = self.Mailbox.search(None, "ALL")
                    if rv != 'OK':
                        self.LogError("No messages found! (search)")
                        if self.WaitForExit("EmailCommandThread", 15):
                            return
                        continue
                    for num in data[0].split():
                        rv, data = self.Mailbox.fetch(num, '(RFC822)')
                        if rv != 'OK':
                            self.LogError("ERROR getting message (fetch): " +
                                          str(num))
                            if self.WaitForExit("EmailCommandThread", 15):
                                return
                            continue
                        if sys.version_info[0] < 3:  #PYTHON 2
                            msg = email.message_from_string(data[0][1])
                        else:  #PYTHON 3
                            msg = email.message_from_bytes(data[0][1])
                        decode_val = email.header.decode_header(
                            msg['Subject'])[0]
                        if sys.version_info[0] < 3:  #PYTHON 2
                            subject = unicode(decode_val[0])
                            subject = subject.decode('utf-8')
                        else:  #PYTHON 3
                            subject = decode_val[0]
                        self.IncomingCallback(subject)

                        # move the message to processed folder
                        result = self.Mailbox.store(
                            num, '+X-GM-LABELS',
                            self.ProcessedFolder)  #add the label
                        self.Mailbox.store(
                            num, '+FLAGS', '\\Deleted'
                        )  # this is needed to remove the original label
                    if self.WaitForExit("EmailCommandThread", 15):
                        return
                except Exception as e1:
                    self.LogErrorLine("Resetting email thread : " + str(e1))
                    if self.WaitForExit("EmailCommandThread", 60):  # 60 sec
                        return
                    break

            if self.WaitForExit("EmailCommandThread", 15):  # 15 sec
                return

            ## end of outer loop

    #------------ MyMail.sendEmailDirectMIME -----------------------------------
    # send email, bypass queue
    def sendEmailDirectMIME(self,
                            msgtype,
                            subjectstr,
                            msgstr,
                            recipient=None,
                            files=None,
                            deletefile=False):

        if recipient == None:
            recipient = self.EmailRecipientByType[msgtype]

        # update date
        dtstamp = datetime.datetime.now().strftime('%a %d-%b-%Y')
        # update time
        tmstamp = datetime.datetime.now().strftime('%I:%M:%S %p')

        msg = MIMEMultipart()
        if self.SenderName == None or not len(self.SenderName):
            msg['From'] = "<" + self.SenderAccount + ">"
        else:
            msg['From'] = self.SenderName + " <" + self.SenderAccount + ">"
            self.LogError(msg['From'])

        try:
            recipientList = recipient.strip().split(",")
            recipientList = map(lambda x: x.strip(), recipientList)
            recipienttemp = ">,<"
            recipienttemp = recipienttemp.join(recipientList)
            recipient = "<" + recipienttemp + ">"
        except Exception as e1:
            self.LogErrorLine("Error parsing recipient format: " + str(e1))
        if self.UseBCC:
            msg['Bcc'] = recipient
        else:
            msg['To'] = recipient
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subjectstr

        body = '\n' + 'Time: ' + tmstamp + '\n' + 'Date: ' + dtstamp + '\n' + msgstr
        msg.attach(MIMEText(body, 'plain', 'us-ascii'))

        # if the files are not found then we skip them but still send the email
        try:
            for f in files or []:

                with open(f, "rb") as fil:
                    part = MIMEApplication(fil.read(), Name=basename(f))
                    part[
                        'Content-Disposition'] = 'attachment; filename="%s"' % basename(
                            f)
                    msg.attach(part)

                if deletefile:
                    os.remove(f)

        except Exception as e1:
            self.LogErrorLine("Error attaching file in sendEmailDirectMIME: " +
                              str(e1))

        #self.LogError("Logging in: SMTP Server <"+self.SMTPServer+">:Port <"+str(self.SMTPPort) + ">")

        try:
            if self.SSLEnabled:
                session = smtplib.SMTP_SSL(self.SMTPServer, self.SMTPPort)
                session.ehlo()
            else:
                session = smtplib.SMTP(self.SMTPServer, self.SMTPPort)
                if not self.TLSDisable:
                    session.starttls()
                session.ehlo
            try:
                if self.debug:
                    pass
                    #session.set_debuglevel(1)     # for some reason login fails when this enabled
            except Exception as e1:
                self.LogErrorLine("Error setting debug level: " + str(e1))
                # this allows support for simple TLS
        except Exception as e1:
            self.LogErrorLine("Error SMTP Init : SSL:<" +
                              str(self.SSLEnabled) + ">: " + str(e1))
            return False

        try:
            if self.EmailPassword != "" and not self.DisableSmtpAuth:
                session.login(str(self.EmailAccount), str(self.EmailPassword))

            if "," in recipient:
                multiple_recipients = recipient.split(",")
                session.sendmail(self.SenderAccount, multiple_recipients,
                                 msg.as_string())
            else:
                session.sendmail(self.SenderAccount, recipient,
                                 msg.as_string())
        except Exception as e1:
            self.LogErrorLine("Error SMTP sendmail: " + str(e1))
            session.quit()
            return False

        session.quit()

        return True
    # end sendEmailDirectMIME()

    #------------MyMail::SendMailThread-----------------------------------------

    def SendMailThread(self):

        # once sendMail is called email messages are queued and then sent from this thread
        time.sleep(0.1)
        while True:

            while self.EmailSendQueue != []:
                MailError = False
                EmailItems = self.EmailSendQueue.pop()
                try:
                    if not (self.sendEmailDirectMIME(
                            EmailItems[0], EmailItems[1], EmailItems[2],
                            EmailItems[3], EmailItems[4], EmailItems[5])):
                        self.LogError(
                            "Error in SendMailThread, sendEmailDirectMIME failed, retrying"
                        )
                        MailError = True
                except Exception as e1:
                    # put the time back at the end of the queue
                    self.LogErrorLine(
                        "Error in SendMailThread, retrying (2): " + str(e1))
                    MailError = True

                if MailError:
                    self.EmailSendQueue.insert(len(self.EmailSendQueue),
                                               EmailItems)
                    # sleep for 2 min and try again
                    if self.WaitForExit("SendMailThread",
                                        120 + self.ExtendWait):
                        return

            if self.WaitForExit("SendMailThread", 2):
                return

    #------------MyMail::sendEmail----------------------------------------------
    # msg type must be one of "outage", "error", "warn", "info"
    def sendEmail(self,
                  subjectstr,
                  msgstr,
                  recipient=None,
                  files=None,
                  deletefile=False,
                  msgtype="error"):

        if not self.DisableEmail:  # if all email disabled, do not queue
            if self.SMTPServer != "" and not self.DisableSMTP:  # if only sending is disabled, do not queue
                self.EmailSendQueue.insert(0, [
                    msgtype, subjectstr, msgstr, recipient, files, deletefile
                ])
Ejemplo n.º 11
0
class GenExercise(MySupport):

    #------------ GenExercise::init---------------------------------------------
    def __init__(self,
                 log=None,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath=MyCommon.DefaultConfPath,
                 host=ProgramDefaults.LocalHost,
                 port=ProgramDefaults.ServerPort,
                 console=None):

        super(GenExercise, self).__init__()

        self.AccessLock = threading.Lock()

        self.log = log
        self.console = console

        self.MonitorAddress = host
        self.PollTime = 2
        self.ExerciseActive = False
        self.Debug = False

        try:
            self.config = MyConfig(filename=os.path.join(
                ConfigFilePath, 'genexercise.conf'),
                                   section='genexercise',
                                   log=self.log)

            self.ExerciseType = self.config.ReadValue('exercise_type',
                                                      default="Normal")
            self.ExerciseHour = self.config.ReadValue('exercise_hour',
                                                      return_type=int,
                                                      default=12)
            self.ExerciseMinute = self.config.ReadValue('exercise_minute',
                                                        return_type=int,
                                                        default=0)
            self.ExerciseDayOfMonth = self.config.ReadValue(
                'exercise_day_of_month', return_type=int, default=1)
            self.ExerciseDayOfWeek = self.config.ReadValue(
                'exercise_day_of_week', default="Monday")
            self.ExerciseDuration = self.config.ReadValue('exercise_duration',
                                                          return_type=float,
                                                          default=12)
            self.ExerciseWarmup = self.config.ReadValue('exercise_warmup',
                                                        return_type=float,
                                                        default=0)
            self.ExerciseFrequency = self.config.ReadValue(
                'exercise_frequency', default="Monthly")
            self.MonitorAddress = self.config.ReadValue(
                'monitor_address', default=ProgramDefaults.LocalHost)
            self.LastExerciseTime = self.config.ReadValue('last_exercise',
                                                          default=None)
            self.UseGeneratorTime = self.config.ReadValue('use_gen_time',
                                                          return_type=bool,
                                                          default=False)
            self.Debug = self.config.ReadValue('debug',
                                               return_type=bool,
                                               default=False)

            # Validate settings
            if not self.ExerciseType.lower() in [
                    "normal", "quiet", "transfer"
            ]:
                self.ExerciseType = "normal"
            if self.ExerciseHour > 23 or self.ExerciseHour < 0:
                self.ExerciseHour = 12
            if self.ExerciseMinute > 59 or self.ExerciseMinute < 0:
                self.ExerciseMinute = 0
            if not self.ExerciseDayOfWeek.lower() in [
                    "monday", "tuesday", "wednesday", "thursday", "friday",
                    "saturday", "sunday"
            ]:
                self.ExerciseDayOfWeek = "Monday"
            if self.ExerciseDayOfMonth > 28 or self.ExerciseDayOfMonth < 1:
                self.ExerciseDayOfMonth = 1
            if self.ExerciseDuration > 60:
                self.ExerciseDuration = 60
            if self.ExerciseDuration < 5:
                self.ExerciseDuration = 5
            if self.ExerciseWarmup > 30:
                self.ExerciseWarmup = 30
            if self.ExerciseWarmup < 0:
                self.ExerciseWarmup = 0
            if not self.ExerciseFrequency.lower() in [
                    "weekly", "biweekly", "monthly"
            ]:
                self.ExerciseFrequency = "Monthly"

            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine(
                "Error reading " +
                os.path.join(ConfigFilePath, "genexercise.conf") + ": " +
                str(e1))
            self.console.error(
                "Error reading " +
                os.path.join(ConfigFilePath, "genexercise.conf") + ": " +
                str(e1))
            sys.exit(1)

        try:

            self.Generator = ClientInterface(host=self.MonitorAddress,
                                             port=port,
                                             log=self.log)

            if not self.CheckGeneratorRequirement():
                self.LogError("Requirements not met. Exiting.")
                sys.exit(1)

            # start thread monitor time for exercise
            self.Threads["ExerciseThread"] = MyThread(self.ExerciseThread,
                                                      Name="ExerciseThread",
                                                      start=False)
            self.Threads["ExerciseThread"].Start()

            try:
                if self.ExerciseFrequency.lower() == "monthly":
                    DayStr = "Day " + str(self.ExerciseDayOfMonth)
                else:
                    DayStr = str(self.ExerciseDayOfWeek)

                self.LogError("Execise: " + self.ExerciseType + ", " +
                              self.ExerciseFrequency + " at " +
                              str(self.ExerciseHour) + ":" +
                              str(self.ExerciseMinute) + " on " + DayStr +
                              " for " + str(self.ExerciseDuration) +
                              " min. Warmup: " + str(self.ExerciseWarmup))
                self.DebugOutput("Debug Enabled")
            except Exception as e1:
                self.LogErrorLine(str(e1))

            signal.signal(signal.SIGTERM, self.SignalClose)
            signal.signal(signal.SIGINT, self.SignalClose)

        except Exception as e1:
            self.LogErrorLine("Error in GenExercise init: " + str(e1))
            self.console.error("Error in GenExercise init: " + str(e1))
            sys.exit(1)

    #----------  GenExercise::SendCommand --------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " +
                              str(Command))
            data = ""

        return data

    #----------  GenExercise::CheckGeneratorRequirement ------------------------
    def CheckGeneratorRequirement(self):

        try:
            data = self.SendCommand("generator: start_info_json")
            StartInfo = {}
            StartInfo = json.loads(data)
            if not "evolution" in StartInfo["Controller"].lower(
            ) and not "nexus" in StartInfo["Controller"].lower():
                self.LogError(
                    "Error: Only Evolution or Nexus controllers are supported for this feature: "
                    + StartInfo["Controller"])
                return False
            return True
        except Exception as e1:
            self.LogErrorLine("Error in CheckGeneratorRequirement: " + str(e1))
            return False

    # ---------- GenExercise::PostWarmup----------------------------------------
    def PostWarmup(self):

        # check to see if the generator is running
        status = self.SendCommand("generator: getbase")
        if not status.lower() in ["running", "exercising"]:
            self.LogError(
                "WARNING: generator not running post warmup. Transfer switch not activated."
            )
            self.SendCommand("generator: setremote=stop")
            return

        self.SendCommand("generator: setremote=starttransfer")
        self.DebugOutput("Starting transfer exercise cycle (post warmup).")
        # set timer to stop
        self.StopTimer = threading.Timer(float(self.ExerciseDuration * 60.0),
                                         self.StopExercise)
        self.StopTimer.start()

    # ---------- GenExercise::ReadyToExercise-----------------------------------
    def ReadyToExercise(self):

        status = self.SendCommand("generator: getbase")
        if not status.lower() in ["ready", "servicedue"]:
            self.LogError(
                "Generator not in Ready state, exercise cycle not started: " +
                str(status))
            return False
        return True

    # ---------- GenExercise::StartExercise-------------------------------------
    def StartExercise(self):

        if self.ExerciseActive:
            # already active
            return

        # Start generator
        if self.ExerciseType.lower() == "normal" and self.ReadyToExercise():
            self.SendCommand("generator: setremote=start")
            self.DebugOutput("Starting normal exercise cycle.")
            self.StopTimer = threading.Timer(
                float(self.ExerciseDuration * 60.0), self.StopExercise)
            self.StopTimer.start()
        elif self.ExerciseType.lower() == "quiet" and self.ReadyToExercise():
            self.SendCommand("generator: setremote=startexercise")
            self.DebugOutput("Starting quiet exercise cycle.")
            self.StopTimer = threading.Timer(
                float(self.ExerciseDuration * 60.0), self.StopExercise)
            self.StopTimer.start()
        elif self.ExerciseType.lower() == "transfer" and self.ReadyToExercise(
        ):
            if self.ExerciseWarmup == 0:
                self.SendCommand("generator: setremote=starttransfer")
                self.DebugOutput("Starting transfer exercise cycle.")
                self.StopTimer = threading.Timer(
                    float(self.ExerciseDuration * 60.0), self.StopExercise)
                self.StopTimer.start()
            else:
                self.SendCommand("generator: setremote=start")
                self.DebugOutput(
                    "Starting warmup for transfer exercise cycle.")
                # start timer for post warmup transition to starttransfer command
                self.WarmupTimer = threading.Timer(
                    float(self.ExerciseWarmup * 60.0), self.PostWarmup)
                self.WarmupTimer.start()
        else:
            self.LogError("Invalid mode in StartExercise: " +
                          str(self.ExerciseType))
            return
        self.WriteLastExerciseTime()
        self.ExerciseActive = True

    # ---------- GenExercise::StopExercise--------------------------------------
    def StopExercise(self):

        if self.ExerciseActive:
            self.SendCommand("generator: setremote=stop")
            self.DebugOutput("Stopping exercise cycle.")
            self.ExerciseActive = False
        else:
            self.DebugOutput("Calling Stop Exercise (not needed)")

    # ---------- GenExercise::DebugOutput-----------------------------
    def DebugOutput(self, Message):

        if self.Debug:
            self.LogError(Message)

    # ---------- GenExercise::WriteLastExerciseTime-----------------------------
    def WriteLastExerciseTime(self):

        try:
            NowString = datetime.datetime.now().strftime(
                "%A %B %d, %Y %H:%M:%S")
            if self.ExerciseFrequency.lower() == "biweekly":
                self.config.WriteValue("last_exercise", NowString)
                self.config.LastExerciseTime = NowString
            self.DebugOutput("Last Exercise Cycle: " + NowString)
        except Exception as e1:
            self.LogErrorLine("Error in WriteLastExerciseTime: " + str(e1))

    # ---------- GenExercise::TimeForExercise-----------------------------------
    def TimeForExercise(self):
        try:
            if self.UseGeneratorTime:
                TimeNow = self.GetGeneratorTime()
            else:
                TimeNow = datetime.datetime.now()
            if TimeNow.hour != self.ExerciseHour or TimeNow.minute != self.ExerciseMinute:
                return False

            weekDays = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
                        "Saturday", "Sunday")

            WeekDayString = weekDays[TimeNow.weekday()]

            if not self.ExerciseFrequency.lower() in [
                    "weekly", "biweekly", "monthly"
            ]:
                self.LogError(
                    "Invalid Exercise Frequency in TimeForExercise: " +
                    str(self.ExerciseFrequency))
                return False
            if self.ExerciseFrequency.lower(
            ) == "weekly" and self.ExerciseDayOfWeek.lower(
            ) == WeekDayString.lower():
                return True
            elif self.ExerciseFrequency.lower(
            ) == "biweekly" and self.ExerciseDayOfWeek.lower(
            ) == WeekDayString.lower():
                if self.LastExerciseTime == None:
                    return True
                LastExerciseTime = datetime.datetime.strptime(
                    self.LastExerciseTime, "%A %B %d, %Y %H:%M:%S")
                if (TimeNow - LastExerciseTime).days >= 14:
                    return True
                return False
            elif self.ExerciseFrequency.lower(
            ) == "monthly" and TimeNow.day == self.ExerciseDayOfMonth:
                return True
            else:
                return False
        except Exception as e1:
            self.LogErrorLine("Error in TimeForExercise: " + str(e1))
        return False

    # ---------- GenExercise::GetGeneratorTime----------------------------------
    def GetGeneratorTime(self):
        try:
            GenTimeStr = ""
            data = self.SendCommand("generator: status_json")
            Status = {}
            Status = json.loads(data)
            TimeDict = self.FindDictValueInListByKey("Time", Status["Status"])
            if TimeDict != None:
                TimeDictStr = self.FindDictValueInListByKey(
                    "Generator Time", TimeDict)
                if TimeDictStr != None or not len(TimeDictStr):
                    GenTimeStr = TimeDictStr
                    # Format is "Wednesday March 6, 2019 13:10" or " "Friday May 3, 2019 11:11"
                    GenTime = datetime.datetime.strptime(
                        GenTimeStr, "%A %B %d, %Y %H:%M")
                else:
                    self.LogError(
                        "Error getting generator time! Genmon may be starting up."
                    )
                    GenTime = datetime.datetime.now()
            else:
                self.LogError("Error getting generator time (2)!")
                GenTime = datetime.datetime.now()
            return GenTime
        except Exception as e1:
            self.LogErrorLine("Error in GetGeneratorTime: " + str(e1) + ": " +
                              GenTimeStr)
            return datetime.datetime.now()

    # ---------- GenExercise::ExerciseThread------------------------------------
    def ExerciseThread(self):

        time.sleep(1)
        while True:
            try:
                if not self.ExerciseActive:
                    if self.TimeForExercise():
                        self.StartExercise()
                if self.WaitForExit("ExerciseThread", float(self.PollTime)):
                    return
            except Exception as e1:
                self.LogErrorLine("Error in ExerciseThread: " + str(e1))
                if self.WaitForExit("ExerciseThread", float(self.PollTime)):
                    return

    # ----------GenExercise::SignalClose----------------------------------------
    def SignalClose(self, signum, frame):

        self.Close()
        sys.exit(1)

    # ----------GenExercise::Close----------------------------------------------
    def Close(self):
        self.KillThread("ExerciseThread")

        if self.ExerciseActive:
            try:
                self.WarmupTimer.cancel()
            except:
                pass
            try:
                self.StopTimer.cancel()
            except:
                pass
            self.StopExercise()
        self.Generator.Close()
Ejemplo n.º 12
0
class GenTemp(MySupport):

    #------------ GenTemp::init-------------------------------------------------
    def __init__(self,
                 log=None,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath=MyCommon.DefaultConfPath,
                 host=ProgramDefaults.LocalHost,
                 port=ProgramDefaults.ServerPort):

        super(GenTemp, self).__init__()

        self.LogFileName = os.path.join(loglocation, "gentemp.log")
        self.AccessLock = threading.Lock()
        # log errors in this module to a file
        self.log = SetupLogger("gentemp", self.LogFileName)

        self.console = SetupLogger("gentemp_console", log_file="", stream=True)

        self.LastValues = {}

        self.MonitorAddress = host
        self.debug = False
        self.PollTime = 1
        self.BlackList = None

        configfile = os.path.join(ConfigFilePath, 'gentemp.conf')
        try:
            if not os.path.isfile(configfile):
                self.LogConsole("Missing config file : " + configfile)
                self.LogError("Missing config file : " + configfile)
                sys.exit(1)

            self.config = MyConfig(filename=configfile,
                                   section='gentemp',
                                   log=self.log)

            self.UseMetric = self.config.ReadValue('use_metric',
                                                   return_type=bool,
                                                   default=False)
            self.PollTime = self.config.ReadValue('poll_frequency',
                                                  return_type=float,
                                                  default=1)
            self.debug = self.config.ReadValue('debug',
                                               return_type=bool,
                                               default=False)
            self.DeviceLabels = self.GetParamList(
                self.config.ReadValue('device_labels', default=None))
            self.BlackList = self.GetParamList(
                self.config.ReadValue('blacklist', default=None))

            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine("Error reading " + configfile + ": " + str(e1))
            self.LogConsole("Error reading " + configfile + ": " + str(e1))
            sys.exit(1)

        try:

            try:
                startcount = 0
                while startcount <= 10:
                    try:
                        self.Generator = ClientInterface(
                            host=self.MonitorAddress, port=port, log=self.log)
                        break
                    except Exception as e1:
                        startcount += 1
                        if startcount >= 10:
                            self.LogConsole("genmon not loaded.")
                            self.LogError("Unable to connect to genmon.")
                            sys.exit(1)
                        time.sleep(1)
                        continue

            except Exception as e1:
                self.LogErrorLine("Error in GenTempThread init: " + str(e1))

            self.DeviceList = self.EnumDevices()

            if not len(self.DeviceList):
                self.LogConsole("No sensors found.")
                self.LogError("No sensors found.")
                sys.exit(1)

            # start thread monitor time for exercise
            self.Threads["GenTempThread"] = MyThread(self.GenTempThread,
                                                     Name="GenTempThread",
                                                     start=False)
            self.Threads["GenTempThread"].Start()

            atexit.register(self.Close)

        except Exception as e1:
            self.LogErrorLine("Error in GenTemp init: " + str(e1))
            self.LogConsole("Error in GenTemp init: " + str(e1))
            sys.exit(1)

    #----------  GenTemp::GetParamList -----------------------------------------
    def GetParamList(self, input_string):

        ReturnValue = []
        try:
            if input_string != None:
                if len(input_string):
                    ReturnList = input_string.strip().split(",")
                    if len(ReturnList):
                        for Items in ReturnList:
                            Items = Items.strip()
                            if len(Items):
                                ReturnValue.append(Items)
                        if len(ReturnValue):
                            return ReturnValue
            return None
        except Exception as e1:
            self.LogErrorLine("Error in GetParamList: " + str(e1))
            return None

    #----------  GenTemp::EnumDevices ------------------------------------------
    def EnumDevices(self):

        DeviceList = []
        try:
            # enum DS18B20 temp sensors
            for sensor in glob.glob("/sys/bus/w1/devices/28-*/w1_slave"):
                if not self.CheckBlackList(sensor) and self.DeviceValid(
                        sensor):
                    self.LogDebug("Found DS18B20 : " + sensor)
                    DeviceList.append(sensor)

            # enum type K thermocouples
            #for sensor in glob.glob("/sys/bus/w1/devices/w1_bus_master*/3b-*/w1_slave"):
            for sensor in glob.glob("/sys/bus/w1/devices/3b-*/w1_slave"):
                if not self.CheckBlackList(sensor) and self.DeviceValid(
                        sensor):
                    self.LogDebug("Found type K thermocouple : " + sensor)
                    DeviceList.append(sensor)
            return DeviceList
        except Exception as e1:
            self.LogErrorLine("Error in EnumDevices: " + str(e1))
            return DeviceList

    #------------ GenTemp::ReadData --------------------------------------------
    def ReadData(self, device):
        try:
            f = open(device, "r")
            data = f.read()
            f.close()
            return data
        except Exception as e1:
            self.LogErrorLine("Error in ReadData for " + device + " : " +
                              str(e1))
            return None

    #------------ GenTemp::DeviceValid -----------------------------------------
    def DeviceValid(self, device):

        try:
            data = self.ReadData(device)

            if isinstance(
                    data, str
            ) and "YES" in data and " crc=" in data and " t=" in data:
                return True
            return False
        except Exception as e1:
            self.LogErrorLine("Error in DeviceValid for " + device + " : " +
                              str(e1))
            return False

    #------------ GenTemp::ParseData -------------------------------------------
    def ParseData(self, data):

        try:
            if self.UseMetric:
                units = "C"
            else:
                units = "F"
            if not isinstance(data, str):
                return None, units
            if not len(data):
                return None, units
            (discard, sep, reading) = data.partition(' t=')
            t = float(reading) / 1000.0
            if not self.UseMetric:
                return self.ConvertCelsiusToFahrenheit(t), units
            else:
                return t, units
        except Exception as e1:
            self.LogErrorLine("Error in ParseData: " + str(e1))
            return None, units

    #------------ GenTemp::GetIDFromDeviceName ---------------------------------
    def GetIDFromDeviceName(self, device):

        try:
            if "28-" in device or "3b-" in device:
                id = device.split("/")[5]
                return id
        except Exception as e1:
            self.LogErrorLine("Error in GetIDFromDeviceName for " + device +
                              " : " + str(e1))
        return "UNKNOWN_ID"

    #----------  GenTemp::SendCommand ------------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " +
                              str(Command))
            data = ""

        return data

    # ---------- GenTemp::CheckBlackList-----------------------------------------
    def CheckBlackList(self, device):

        if not isinstance(self.BlackList, list):
            return False
        return any(blacklistitem in device for blacklistitem in self.BlackList)

    # ---------- GenTemp::GenTempThread-----------------------------------------
    def GenTempThread(self):

        time.sleep(1)

        while True:
            try:
                labelIndex = 0
                ReturnDeviceData = []
                for sensor in self.DeviceList:
                    temp, units = self.ParseData(self.ReadData(sensor))
                    if temp != None:
                        self.LogDebug(
                            "Device: %s Reading: %.2f %s" %
                            (self.GetIDFromDeviceName(sensor), temp, units))
                        if isinstance(self.DeviceLabels, list) and len(
                                self.DeviceLabels) and (labelIndex < len(
                                    self.DeviceLabels)):
                            device_label = self.DeviceLabels[labelIndex]
                        else:
                            device_label = self.GetIDFromDeviceName(sensor)
                        ReturnDeviceData.append(
                            {device_label: "%.2f %s" % (temp, units)})
                    labelIndex += 1
                return_string = json.dumps(
                    {"External Temperature Sensors": ReturnDeviceData})
                self.SendCommand("generator: set_temp_data=" + return_string)

                self.LogDebug(return_string)
                if self.WaitForExit("GenTempThread", float(self.PollTime)):
                    return

            except Exception as e1:
                self.LogErrorLine("Error in GenTempThread: " + str(e1))
                if self.WaitForExit("GenTempThread",
                                    float(self.PollTime * 60)):
                    return

    # ----------GenTemp::Close----------------------------------------------
    def Close(self):
        self.LogError("GenTemp Exit")
        self.KillThread("GenTempThread")
        self.Generator.Close()
Ejemplo n.º 13
0
class GenTankData(MySupport):

    # The device is the ADS1115 I2C ADC
    # reference python http://www.smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION = 0x1
    POINTER_LOW_THRESHOLD = 0x2
    POINTER_HIGH_THRESHOLD = 0x3

    #------------ GenTankData::init---------------------------------------------
    def __init__(self,
                 log=None,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath=MyCommon.DefaultConfPath,
                 host=ProgramDefaults.LocalHost,
                 port=ProgramDefaults.ServerPort):

        super(GenTankData, self).__init__()

        self.LogFileName = os.path.join(loglocation, "gentankdiy.log")
        self.AccessLock = threading.Lock()
        # log errors in this module to a file
        self.log = SetupLogger("gentankdiy", self.LogFileName)

        self.console = SetupLogger("gentankdiy_console",
                                   log_file="",
                                   stream=True)

        self.MonitorAddress = host
        self.PollTime = 2
        self.debug = False

        configfile = os.path.join(ConfigFilePath, 'gentankdiy.conf')
        try:
            if not os.path.isfile(configfile):
                self.LogConsole("Missing config file : " + configfile)
                self.LogError("Missing config file : " + configfile)
                sys.exit(1)

            self.config = MyConfig(filename=configfile,
                                   section='gentankdiy',
                                   log=self.log)

            self.PollTime = self.config.ReadValue('poll_frequency',
                                                  return_type=float,
                                                  default=60)
            self.debug = self.config.ReadValue('debug',
                                               return_type=bool,
                                               default=False)
            self.i2c_address = self.config.ReadValue('i2c_address',
                                                     return_type=int,
                                                     default=72)
            self.mv_per_step = self.config.ReadValue('mv_per_step',
                                                     return_type=int,
                                                     default=125)
            self.Multiplier = self.config.ReadValue(
                'volts_to_percent_multiplier', return_type=float, default=20.0)
            # I2C channel 1 is connected to the GPIO pins
            self.i2c_channel = self.config.ReadValue('i2c_channel',
                                                     return_type=int,
                                                     default=1)

            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine("Error reading " + configfile + ": " + str(e1))
            self.LogConsole("Error reading " + configfile + ": " + str(e1))
            sys.exit(1)

        try:

            try:
                startcount = 0
                while startcount <= 10:
                    try:
                        self.Generator = ClientInterface(
                            host=self.MonitorAddress, port=port, log=self.log)
                        break
                    except Exception as e1:
                        startcount += 1
                        if startcount >= 10:
                            self.console.info("genmon not loaded.")
                            self.LogError("Unable to connect to genmon.")
                            sys.exit(1)
                        time.sleep(1)
                        continue

            except Exception as e1:
                self.LogErrorLine("Error in GenTankData init: " + str(e1))

            # start thread monitor time for exercise
            self.Threads["TankCheckThread"] = MyThread(self.TankCheckThread,
                                                       Name="TankCheckThread",
                                                       start=False)

            if not self.InitADC():
                self.LogError("InitADC failed, exiting")
                sys.exit(1)

            self.Threads["TankCheckThread"].Start()

            atexit.register(self.Close)
            signal.signal(signal.SIGTERM, self.Close)
            signal.signal(signal.SIGINT, self.Close)

        except Exception as e1:
            self.LogErrorLine("Error in GenTankData init: " + str(e1))
            self.console.error("Error in GenTankData init: " + str(e1))
            sys.exit(1)

    #----------  GenTankData::SendCommand --------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " +
                              str(Command))
            data = ""

        return data

    # ---------- GenTankData::InitADC-------------------------------------------
    def InitADC(self):

        try:

            # I2C channel 1 is connected to the GPIO pins
            self.I2Cbus = smbus.SMBus(self.i2c_channel)

            # Reset ADC
            self.I2Cbus.write_byte(self.RESET_ADDRESS, self.RESET_COMMAND)

            # set config register  and start conversion
            # ANC1 and GND, 4.096v, 128s/s
            # Customized - Port A0 and 4.096 V input
            # 0b11000011; # bit 15-8  = 0xC3
            # bit 15 flag bit for single shot
            # Bits 14-12 input selection:
            # 100 ANC0; 101 ANC1; 110 ANC2; 111 ANC3
            # Bits 11-9 Amp gain. Default to 010 here 001 P19
            # Bit 8 Operational mode of the ADS1115.
            # 0 : Continuous conversion mode
            # 1 : Power-down single-shot mode (default)
            CONFIG_VALUE_1 = 0xC3
            # bits 7-0  0b10000101 = 0x85
            # Bits 7-5 data rate default to 100 for 128SPS
            # Bits 4-0  comparator functions see spec sheet.
            CONFIG_VALUE_2 = 0x85
            self.I2Cbus.write_i2c_block_data(self.i2c_address,
                                             self.POINTER_CONFIGURATION,
                                             [CONFIG_VALUE_1, CONFIG_VALUE_2])

            self.LogDebug("I2C Init complete: success")

        except Exception as e1:
            self.LogErrorLine("Error calling InitADC: " + str(e1))
            return False

        return True

    # ---------- GenTankData::GetGaugeData--------------------------------------
    def GetGaugeData(self):
        try:

            val = self.I2Cbus.read_i2c_block_data(self.i2c_address,
                                                  self.POINTER_CONVERSION, 2)

            self.LogDebug(str(val))
            # convert display results
            reading = val[0] << 8 | val[1]

            if (reading < 0):
                reading = 0

            #reading = self.I2Cbus.read_word_data(self.i2c_address, self.i2c_channel)
            volts = round(
                float(reading * (float(self.mv_per_step) / 1000000.0)), 2)
            gauge_data = float(self.Multiplier) * volts
            self.LogDebug("Reading Gauge Data: %4.2f%%" % gauge_data)
            return gauge_data

        except Exception as e1:
            self.LogErrorLine("Error calling  GetGaugeData: " + str(e1))
            return 0.0

    # ---------- GenTankData::TankCheckThread-----------------------------------
    def TankCheckThread(self):

        time.sleep(1)

        while True:
            try:

                dataforgenmon = {}

                tankdata = self.GetGaugeData()
                if tankdata != None:
                    dataforgenmon["Tank Name"] = "External Tank"
                    dataforgenmon["Capacity"] = 0
                    dataforgenmon["Percentage"] = self.GetGaugeData()

                    retVal = self.SendCommand("generator: set_tank_data=" +
                                              json.dumps(dataforgenmon))
                    self.LogDebug(retVal)
                if self.WaitForExit("TankCheckThread",
                                    float(self.PollTime * 60)):
                    return
            except Exception as e1:
                self.LogErrorLine("Error in TankCheckThread: " + str(e1))
                if self.WaitForExit("TankCheckThread",
                                    float(self.PollTime * 60)):
                    return

    # ----------GenTankData::Close----------------------------------------------
    def Close(self):
        self.KillThread("TankCheckThread")
        self.Generator.Close()
Ejemplo n.º 14
0
class GenCTHat(MySupport):

    #------------ GenCTHat::init------------------------------------------------
    def __init__(self,
                 log=None,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath=MyCommon.DefaultConfPath,
                 host=ProgramDefaults.LocalHost,
                 port=ProgramDefaults.ServerPort,
                 console=None):

        super(GenCTHat, self).__init__()

        #https://tutorials-raspberrypi.com/mcp3008-read-out-analog-signals-on-the-raspberry-pi/
        #https://forums.raspberrypi.com/viewtopic.php?t=237182

        self.LogFileName = os.path.join(loglocation, "gencthat.log")
        self.AccessLock = threading.Lock()

        self.log = log
        self.console = console

        self.MonitorAddress = host
        self.PollTime = 2
        self.SampleTimeMS = 34
        self.debug = False
        self.ConfigFileName = 'gencthat.conf'
        configfile = os.path.join(ConfigFilePath, self.ConfigFileName)
        try:
            if not os.path.isfile(configfile):
                self.LogConsole("Missing config file : " + configfile)
                self.LogError("Missing config file : " + configfile)
                sys.exit(1)

            self.config = MyConfig(filename=configfile,
                                   section='gencthat',
                                   log=self.log)

            self.Multiplier = self.config.ReadValue('multiplier',
                                                    return_type=float,
                                                    default=0.488)
            # this checks to see if an old version of the conf file is in use and replaces it
            if self.Multiplier == 0.218:
                self.ConfPath = os.path.join(
                    os.path.dirname(os.path.realpath(__file__)), "conf")
                if os.path.isfile(
                        os.path.join(self.ConfPath, self.ConfigFileName)):
                    copyfile(os.path.join(self.ConfPath, self.ConfigFileName),
                             configfile)
                    self.LogError(
                        "Copied " +
                        os.path.join(self.ConfPath, self.ConfigFileName) +
                        " to " + configfile)
                    self.config = MyConfig(filename=configfile,
                                           section='gencthat',
                                           log=self.log)
                else:
                    self.LogError(
                        "Error: unable to find config file: " +
                        os.path.join(self.ConfPath, self.ConfigFileName))

            self.SampleTimeMS = self.config.ReadValue('sample_time_ms',
                                                      return_type=int,
                                                      default=34)
            self.Multiplier = self.config.ReadValue('multiplier',
                                                    return_type=float,
                                                    default=0.488)
            self.PollTime = self.config.ReadValue('poll_frequency',
                                                  return_type=float,
                                                  default=60)
            self.powerfactor = self.config.ReadValue('powerfactor',
                                                     return_type=float,
                                                     default=1.0)
            self.bus = self.config.ReadValue('bus', return_type=int, default=1)
            self.device = self.config.ReadValue('device',
                                                return_type=int,
                                                default=0)
            self.strict = self.config.ReadValue('strict',
                                                return_type=bool,
                                                default=False)
            self.singlelegthreshold = self.config.ReadValue(
                'singlelegthreshold', return_type=float, default=0.6)
            self.debug = self.config.ReadValue('debug',
                                               return_type=bool,
                                               default=False)

            self.LogDebug("Multiplier: " + str(self.Multiplier))
            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine("Error reading " + configfile + ": " + str(e1))
            self.LogConsole("Error reading " + configfile + ": " + str(e1))
            sys.exit(1)

        try:

            self.adc = MCP3008(bus=self.bus, device=self.device, log=self.log)
            self.adc.open()

            self.Generator = ClientInterface(host=self.MonitorAddress,
                                             port=port,
                                             log=self.log)

            #if not self.CheckGeneratorRequirement():
            #    self.LogError("Requirements not met. Exiting.")
            #    sys.exit(1)

            # start thread monitor time for exercise
            self.Threads["SensorCheckThread"] = MyThread(
                self.SensorCheckThread, Name="SensorCheckThread", start=False)
            self.Threads["SensorCheckThread"].Start()

            signal.signal(signal.SIGTERM, self.SignalClose)
            signal.signal(signal.SIGINT, self.SignalClose)

        except Exception as e1:
            self.LogErrorLine("Error in GenCTHat init: " + str(e1))
            self.console.error("Error in GenCTHat init: " + str(e1))
            sys.exit(1)

    #----------  GenCTHat::SendCommand -----------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " +
                              str(Command))
            data = ""

        return data

    #----------  GenCTHat::CheckGeneratorRequirement ---------------------------
    def CheckGeneratorRequirement(self):

        try:
            data = self.SendCommand("generator: start_info_json")
            StartInfo = {}
            StartInfo = json.loads(data)
            if not "evolution" in StartInfo["Controller"].lower(
            ) and not "nexus" in StartInfo["Controller"].lower():
                self.LogError(
                    "Error: Only Evolution or Nexus controllers are supported for this feature: "
                    + StartInfo["Controller"])
                return False
            return True
        except Exception as e1:
            self.LogErrorLine("Error in CheckGeneratorRequirement: " + str(e1))
            return False

    # ---------- GenCTHat::MillisecondsElapsed----------------------------------
    def MillisecondsElapsed(self, ReferenceTime):

        CurrentTime = datetime.datetime.now()
        Delta = CurrentTime - ReferenceTime
        return Delta.total_seconds() * 1000

    # ---------- GenCTHat::SensorCheckThread------------------------------------
    def SensorCheckThread(self):

        time.sleep(1)
        while True:
            try:
                CT1 = None
                CT2 = None
                CTReading1 = []
                CTReading2 = []

                for i in range(5):
                    CT1 = self.GetCTReading(channel=0)
                    if CT1 != None:
                        CTReading1.append(CT1)
                    CT2 = self.GetCTReading(channel=1)
                    if CT2 != None:
                        CTReading2.append(CT2)

                if len(CTReading1):
                    CT1 = min(CTReading1)
                else:
                    CT1 = None
                if len(CTReading2):
                    CT2 = min(CTReading2)
                else:
                    CT2 = None

                if CT1 == None or CT2 == None:
                    if self.WaitForExit("SensorCheckThread",
                                        float(self.PollTime)):
                        return
                    continue

                if CT1 <= self.singlelegthreshold:
                    CT1 = 0
                if CT2 <= self.singlelegthreshold:
                    CT2 = 0

                self.LogDebug("CT1: %.2f, CT2: %.2f" % (CT1, CT2))

                data = {}
                data['strict'] = self.strict
                data['current'] = CT1 + CT2
                data['ctdata'] = [CT1, CT2]
                data['powerfactor'] = self.powerfactor
                return_string = json.dumps(data)
                self.Generator.ProcessMonitorCommand(
                    "generator: set_power_data=" + return_string)

                if self.WaitForExit("SensorCheckThread", float(self.PollTime)):
                    return
            except Exception as e1:
                self.LogErrorLine("Error in SensorCheckThread: " + str(e1))
                if self.WaitForExit("SensorCheckThread", float(self.PollTime)):
                    return

    # ----------GenCTHat::GetCTReading------------------------------------------
    def GetCTReading(self, channel=0):

        try:
            StartTime = datetime.datetime.now()
            num_samples = 0
            max = 0
            min = 512
            return_data = 0
            while True:

                sample = self.adc.read(channel=channel)

                if sample > max:
                    max = sample
                if sample < min:
                    min = sample
                num_samples += 1

                msElapsed = self.MillisecondsElapsed(StartTime)
                if msElapsed > self.SampleTimeMS:
                    break

            if max == 0 and min == 512:
                self.LogDebug("No data read in GetCTSample")
                return 0
            else:
                offset = max - 512
                if 511 - min > offset:
                    offset = 511 - min
                if offset <= 2:
                    offset = 0  #1 or 2 is most likely just noise on the clamps or in the traces on the board

            self.LogDebug(
                "channel: %d, sample: %d, max: %d, min: %d, ms elapsed: %d, num samples %d"
                % (channel, sample, max, min, msElapsed, num_samples))

            if max == min == 0:
                self.LogDebug("NULL readings, device not responding")
                return None
            return_data = offset * self.Multiplier
            return return_data

        except Exception as e1:
            self.LogErrorLine("Error in GetCTReading: " + str(e1))
            return 0

    # ----------GenCTHat::SignalClose-------------------------------------------
    def SignalClose(self, signum, frame):

        self.Close()
        sys.exit(1)

    # ----------GenCTHat::Close-------------------------------------------------
    def Close(self):
        self.KillThread("SensorCheckThread")
        self.Generator.Close()
Ejemplo n.º 15
0
class MyModem(MySupport):
    def __init__(self,
            port = "/dev/ttyAMA0" ,
            rate = 115200,
            loglocation = ProgramDefaults.LogPath,
            log = None,
            localinit = False,
            ConfigFilePath = ProgramDefaults.ConfPath,
            recipient = None):
        super(MyModem, self).__init__()

        self.MessagesSent = 0
        self.Errors = 0
        self.SendActive = False
        self.ModemLock = threading.RLock()
        self.Sending = False
        self.SendQueue = []

        if ConfigFilePath == None:
            self.ConfigFilePath = ProgramDefaults.ConfPath
        else:
            self.ConfigFilePath = ConfigFilePath

        # log errors in this module to a file
        if localinit == True:
            self.configfile = "mymodem.conf"
        else:
            self.configfile = os.path.join(self.ConfigFilePath, "mymodem.conf")

        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("mymodem", os.path.join(loglocation, "mymodem.log"))
        else:
            self.log = log

        self.console = SetupLogger("mymodem_console", log_file = "", stream = True)

        try:
            self.config = MyConfig(filename = self.configfile, section = "MyModem", log = self.log)

            self.LogAtCommands = self.config.ReadValue('log_at_commands', return_type = bool, default = False)

            self.MessageLevel = self.config.ReadValue('message_level', default = 'error')

            self.Rate = self.config.ReadValue('rate', return_type = int, default = 115200)

            self.Port = self.config.ReadValue('port', default = "/dev/ttyAMA0")

            self.Recipient = self.config.ReadValue('recipient', default = recipient)

            self.ModemType = self.config.ReadValue('modem_type', default = "LTEPiHat")

        except Exception as e1:
            self.LogErrorLine("Error reading config file: " + str(e1))
            self.LogConsole("Error reading config file: " + str(e1))
            return

        if self.Recipient == None or not len(self.Recipient):
            self.LogErrorLine("Error invalid recipient")
            self.LogConsole("Error invalid recipient")

        if self.Port == None or not len(self.Port):
            self.LogErrorLine("Error invalid port")
            self.LogConsole("Error invalid port")
            return

        if self.Rate == None or self.Rate <= 0:
            self.LogErrorLine("Error invalid rate")
            self.LogConsole("Error invalid rate")
            return

        # rate * 10 bits then convert to MS
        self.CharacterTimeMS = (((1/ self.Rate) * 10)  *1000)

        self.InitComplete = False

        try:
            self.SerialDevice = SerialDevice(port, rate = rate, log = self.log, loglocation = loglocation)
            self.Threads = self.MergeDicts(self.Threads, self.SerialDevice.Threads)

            self.Threads["SendMessageThread"] = MyThread(self.SendMessageThread, Name = "SendMessageThread")

        except Exception as e1:
            self.LogErrorLine("Error opening serial device in MyModem: " + str(e1))

    #------------MyModem::GetConfig---------------------------------------------
    def GetConfig(self):
        return self.config

    #------------MyModem::SendMessageThread-------------------------------------
    def SendMessageThread(self):

        # once SendMessage is called messages are queued and then sent from this thread
        time.sleep(0.5)
        while True:
            try:
                self.SendActive = False
                if self.WaitForExit("SendMessageThread", 2 ):
                    return

                while self.SendQueue != []:
                    SendError = False

                    if not self.InitComplete:
                        if self.WaitForExit("SendMessageThread", 5 ):
                            return
                        else:
                            continue

                    self.SendActive = True
                    MessageItems = self.SendQueue.pop()
                    try:
                        if not (self.SendSMS(message = MessageItems[0], recipient = MessageItems[1] , msgtype = MessageItems[2])):
                            self.LogError("Error in SendMessageThread, SendSMS failed, retrying")
                            SendError = True
                    except Exception as e1:
                        # put the time back at the end of the queue
                        self.LogErrorLine("Error in SendMessageThread, retrying (2): " + str(e1))
                        SendError = True

                    if SendError:
                        self.SendQueue.insert(len(self.SendQueue),MessageItems)
                        self.SendActive = False
                        # sleep for 10 sec and try again
                        if self.WaitForExit("SendMessageThread", 10 ):
                            return
            except Exception as e1:
                self.LogErrorLine("Error in SendMessageThread: " + str(e1))

    #------------MyModem::SendMessage-------------------------------------------
    # msgtype must be one of "outage", "error", "warn", "info"
    def SendMessage(self, message = None, recipient = None, msgtype = "error"):

        try:
            self.SendQueue.insert(0,[message, recipient, msgtype])
            return True
        except Exception as e1:
            self.LogErrorLine("Error in SendMessage: " + str(e1))
            return False

    #------------------MyModem::MessagesPending---------------------------------
    def MessagesPending(self):

        return self.SendQueue != [] or self.SendActive

    #------------------MyModem::SendCommand-------------------------------------
    def SendATCommand(self, command, response = None, retries = 1, NoAddCRLF = False):

        try:

            if self.SerialDevice == None:
                self.LogError("Serial device is not open!")
                return False

            if not NoAddCRLF:
                command = str(command) + str("\r\n")
                if response != None:
                    response = str(response) + str("\r\n")
            else:
                command = str(command)
                if response != None:
                    response = str(response)
            with self.ModemLock:
                self.Sending = True
                self.SerialDevice.Flush()

                attempts = retries
                while  self.Sending and attempts >= 0:
                    self.SerialDevice.Write(command.encode())
                    if self.LogAtCommands:
                        self.LogError("->" + command)
                    time.sleep(0.75)
                    if None != response:
                        SerialBuffer = self.SerialDevice.GetRxBufferAsString()

                        if self.LogAtCommands and len(SerialBuffer):
                            self.LogError("<-" + SerialBuffer)

                        if SerialBuffer.find("ERROR") >= 0:
                            self.Sending = False
                            self.LogError("Error returned SendATCommand: CMD: " + str(command))
                            return False

                        if SerialBuffer.find(response) >= 0:
                            self.Sending = False
                            attempts += 1

                    elif None == response:
                        self.Sending = False

                    if self.Sending:
                        time.sleep(0.5)
                        attempts = attempts - 1
                    else:
                        break

                return (attempts >= 0)

        except Exception as e1:
            self.LogErrorLine("Error in SendATCommand: " + "CMD: " + str(command) + " : "+ str(e1))
            return False

    #------------------MyModem::Send--------------------------------------------
    def SendSMS(self, message = None, recipient = None, msgtype = "error"):

        try:

            if recipient == None:
                recipient = self.Recipient

            if recipient == None or not len(recipient):
                self.LogError("Invalid recipient in SendSMS.")
                return False

            with self.ModemLock:
                # set default config
                if not self.SendATCommand("ATZ", "OK"):
                    self.LogError("Failed setting default config in MySMS:Send")
                    self.Errors += 1

                # set text message mode
                if not self.SendATCommand("AT+CMGF=1", "OK"):
                    self.LogError("Failed setting message mode in MySMS:Send")
                    self.Errors += 1
                    return False

                StartMessage = str("AT+CMGS=" + '"' + str(recipient) + '"' + "\r")
                if not self.SendATCommand(StartMessage, ">", retries = 0,  NoAddCRLF = True):
                    self.SendATCommand("\x1b" , "OK", retries = 1,  NoAddCRLF = True)
                    self.LogError("Failed sending CMGS in MySMS:Send")
                    self.Errors += 1
                    return False

                if not self.SendATCommand(str(message) + "\r" , ">", retries = 0,  NoAddCRLF = True):
                    self.SendATCommand("\x1b" , "OK", retries = 1,  NoAddCRLF = True)
                    self.LogError("Failed sending Message Body in MySMS:Send")
                    self.Errors += 1
                    return False

                if not self.SendATCommand("\x1a" , "OK", retries = 1,  NoAddCRLF = True):
                    self.SendATCommand("\x1b" , "OK", retries = 1,  NoAddCRLF = True)
                    self.LogError("Failed sending EOM in MySMS:Send")
                    self.Errors += 1
                    return False

                self.SendATCommand("AT", 'OK')
                self.MessagesSent += 1
            return True
        except Exception as e1:
            self.Errors += 1
            self.LogErrorLine("Error in MySMS:Send: " + str(e1))
            return False
    #------------------MyModem::GetQuotedString---------------------------------
    def GetQuotedString(self, InputString):

        try:
            quoted = re.compile('"[^"]*"')
            for value in quoted.findall(InputString):
                newline = "".join( c for c in value if  c not in '"' )
                return newline

            return None
        except Exception as e1:
            self.LogErrorLine("Error in GetQuotedString: " + str(InputString) + ": " + str(e1))
            return ""
    #------------------MyModem::GetNumbersFromString----------------------------
    def GetNumbersFromString(self, InputString):
        # return list of numbers
        try:
            return re.findall(r'\d+', InputString)
        except Exception as e1:
            self.LogErrorLine("Error in GetNumbersFromString: " + str(InputString) + ": " + str(e1))
            return []

    #------------------MyModem::GetItemsFromCommand-----------------------------
    def GetItemsFromCommand(self, InputString):

        try:
            ReturnString = InputString
            Index = ReturnString.find(":")
            if Index > 1 or len(ReturnString) < 2:
                ListItems = ReturnString[Index + 1 :].split(",")
                ListItems = map(str.strip, ListItems)
                return ListItems
            else:
                return [InputString.split('\r\n')[1].strip()]
        except Exception as e1:
            self.LogErrorLine("Error in GetItemsFromCommand: " + str(InputString) + ": " + str(e1))
            self.LogErrorLine("Input: " + str(InputString))
            return []

    #------------------MyModem::GetInfo-----------------------------------------
    def GetInfo(self, ReturnString = False):
        ModemInfo = collections.OrderedDict()
        try:
            with self.ModemLock:
                ModemInfo["Port"] = str(self.Port)
                ModemInfo["Rate"] = str(self.Rate)
                ModemInfo["Messages Sent"] = str(self.MessagesSent)
                ModemInfo["Errors"] = str(self.Errors)

                # get operator name
                if self.SendATCommand("AT+COPS?","OK" ):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ModemInfo["Carrier"] = self.GetQuotedString(Buffer.split('\r\n')[1])

                # AT+CIMI IMSI (International mobile subscriber identification)
                if self.SendATCommand("AT+CIMI","OK" ):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        ModemInfo["IMSI"] = ReturnValue[0]

                ## get SIM card state
                if self.SendATCommand("AT+UUICC?", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        SIMType = self.GetNumbersFromString(ReturnValue[0])[0]
                        if SIMType == "0":
                            ModemInfo["SIM Type"] = "2G"
                        elif SIMType == "1":
                            ModemInfo["SIM Type"] = "3G or 4G"


                # name of manufacturer (AT+CGMI)
                if self.SendATCommand("AT+CGMI", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        ModemInfo["Manufacturer"] = ReturnValue[0]

                # show module/model name
                if self.SendATCommand("AT+CGMM", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        ModemInfo["Model"] = ReturnValue[0]

                # phone / modem info

                # IMEI number (International Mobile Equipment Identity) (AT+CGSN)
                if self.SendATCommand("AT+CGSN", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        ModemInfo["IMEI"] = ReturnValue[0]

                # software version (AT+CGMR)
                if self.SendATCommand("AT+CGMR", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue):
                        ModemInfo["Firmware Version"] = ReturnValue[0]

                ## subscriber info MSISDN (AT+CNUM)
                if self.SendATCommand("AT+CNUM", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    ReturnValue = self.GetItemsFromCommand(Buffer)
                    if len(ReturnValue) >= 2:
                        ModemInfo["MSISDN"] = self.GetQuotedString(ReturnValue[1])

                # mobile phone activity status (AT+CPAS),  returns "+CPAS: 0" where number is:
                #    0: ready (MT allows commands from DTE)
                #    1: unavailable (MT does not allow commands from
                #    2: unknown (MT is not guaranteed to respond to instructions)
                #    3: ringing (MT is ready for commands from DTE, but the ringer is active)
                #    4:callinprogress(MTisreadyforcommandsfromDTE,butacallisinprogress,e.g.callactive,
                #    hold, disconnecting)
                #    5:asleep(MEisunabletoprocesscommandsfromDTEbecauseitisinalowfunctionalitystate)
                if self.SendATCommand("AT+CPAS", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    NumberList = self.GetItemsFromCommand(Buffer)
                    if len(NumberList) >= 1:
                        Status = self.GetNumbersFromString(NumberList[0])[0]
                        if Status == "0":
                            ModemInfo["Status"] = "Ready"
                        elif Status == "1":
                            ModemInfo["Status"] = "Unavailable"
                        elif Status == "2":
                            ModemInfo["Status"] = "Unknown"
                        elif Status == "3":
                            ModemInfo["Status"] = "Ringing"
                        elif Status == "4":
                            ModemInfo["Status"] = "Call In Progress"
                        elif Status == "5":
                            ModemInfo["Status"] = "Asleep"
                        else:
                            ModemInfo["Status"] = "Unknown"

                # mobile network registration status (AT+CREG?) returns "+CREG: 0,0" or +CREG: n,stat
                #    <n>
                #    0 (default value and factory-programmed value): network registration URC disabled
                #    1: network registration URC +CREG: <stat> enabled
                #    2: network registration and location information URC +CREG: <stat>[,<lac>,<ci>[,<AcTStatus>]] enabled
                #    <stat>
                #    0: not registered, the MT is not currently searching a new operator to register to
                #    1: registered, home network
                #    2: not registered, but the MT is currently searching a new operator to register to
                #    3: registration denied
                #    4: unknown (e.g. out of GERAN/UTRAN/E-UTRAN coverage)
                #    5: registered, roaming
                #    6:registeredfor"SMSonly",homenetwork(applicableonlywhen<AcTStatus>indicates E-UTRAN)
                #    7:registeredfor"SMSonly",roaming(applicableonlywhen<AcTStatus>indicatesE-UTRAN)
                #    8: attached for emergency bearer services only
                #    9:registeredfor"CSFBnotpreferred",homenetwork(applicableonlywhen<AcTStatus> indicates E-UTRAN)
                #    10:registeredfor"CSFBnotpreferred",roaming(applicableonlywhen<AcTStatus>indicates E-UTRAN)

                ## AT+REG=2
                self.SendATCommand("AT+CREG=2", "OK")

                ## +CREG, +CEREG and +CGREG.
                if self.SendATCommand("AT+CREG?", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    NumberList = self.GetItemsFromCommand(Buffer)
                    if len(NumberList) >= 1:
                        if NumberList[0] == "0":
                            ModemInfo["Registration Status"] = "Disabled"
                        elif NumberList[0] == "1" or NumberList[0] == "2":
                            ModemInfo["Registration Status"] = "Enabled"
                    if len(NumberList) >= 2:
                        NetworkRegistrationLookup = {
                            "0" : "Not Registered, Not searching",
                            "1" : "Registered, Home network",
                            "2" : "Not Registered, Searching",
                            "3" : "Registration Denied",
                            "4" : "Unknown, Out of Coverage",
                            "5" : "Registered, Roaming",
                            "6" : "Registered, Home network, SMS Only",
                            "7" : "Registered, Roaming, SMS Only",
                            "8" : "Attached for Emergency Bearer Services Only",
                            "9" : "Registered, Home network, CSFB Not Preferred",
                            "10" : "Registered, Roaming, CSFB Not Preferred",
                        }

                        ModemInfo["Network Registration"] = NetworkRegistrationLookup.get(NumberList[1], "Unknown")

                    if len(NumberList) > 5:
                        NetworkTech ={
                            "0" : "GSM",                        # 2G
                            "1" : "GSM Compact",                # 2G
                            "2" : "UTRAN",                      # 3G
                            "3" : "GSM w/EGPRS",                # 2.5G
                            "4" : "UTRAN w/HSDPA",              # 3G
                            "5" : "UTRAN w/HSUPA",              # 3G
                            "6" : "UTRAN w/HSDPA and HSUPA",    # 3G
                            "7" : "E-UTRAN",                    # 4G
                            "255" : "Unknown"
                        }
                        ModemInfo["Cell Network Technology"] = NetworkTech.get(self.GetNumbersFromString(NumberList[4])[0], "Unknown")

                # radio signal strength (AT+CSQ), returns "+CSQ: 2,5"
                # first number is RSSI:
                #    The allowed range is 0-31 and 99. Remapped indication of the following parameters:
                #    the Received Signal Strength Indication (RSSI) in GSM RAT
                #    the Received Signal Code Power (RSCP) in UMTS RAT
                #    the Reference Signal Received Power (RSRP) in LTE RAT
                #    When the RF power level of the received signal is the highest possible, the value 31 is reported. When it is not known, not detectable or currently not available, 99 is returned.
                # second number is signal quality:
                #   The allowed range is 0-7 and 99. The information provided depends on the selected RAT:
                #   In 2G RAT CS dedicated and GPRS packet transfer mode indicates the BitErrorRate(BER)as
                #   specified in 3GPP TS 45.008 [148]
                #   In 2G RAT EGPRS packet transfer mode indicates the Mean BitErrorProbability(BEP) of a radio
                #   block. 3GPP TS 45.008 [148] specifies the range 0-31 for the Mean BEP which is mapped to
                #   the range 0-7 of <qual>
                #   In UMTS RAT indicates the Energy per Chip/Noise(ECN0) ratioin dB levels of the current cell.
                #   3GPP TS 25.133 [106] specifies the range 0-49 for EcN0 which is mapped to the range 0-7
                #   of <qual>
                #   In LTE RAT indicates the Reference Signal Received Quality(RSRQ). TS36.133[105] specifies
                #   the range 0-34 for RSRQ which is mapped to the range 0-7 of <qual>

                if self.SendATCommand("AT+CSQ", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    NumberList = self.GetItemsFromCommand(Buffer)

                    if len(NumberList) >= 2:
                        RSSIList = self.ParseRSSI(NumberList[0])
                        ModemInfo["RSSI"] = RSSIList[0] + " dBm" + ", " + RSSIList[1]
                        ModemInfo["Signal Quality"] = self.GetNumbersFromString(NumberList[1])[0]

                if self.SendATCommand("AT+CCLK?", "OK"):
                    Buffer = self.SerialDevice.GetRxBufferAsString()
                    if len(Buffer):
                        ModemInfo["Network Time"] = self.GetQuotedString(Buffer)


        except Exception as e1:
            self.LogErrorLine("Error in MyModem:GetInfo: " + str(e1))

        if ReturnString:
            return self.DictToString(ModemInfo)
        return ModemInfo
    #------------------MyModem::ParseRSSI-------------------------------------------
    def ParseRSSI(self, Value):

        RSSILookup = {
            "0" : ["-113", "Poor"],
            "1" : ["-111", "Poor"],
            "2" : ["-109", "Marginal"],
            "3" : ["-107", "Marginal"],
            "4" : ["-105", "Marginal"],
            "5" : ["-103", "Marginal"],
            "6" : ["-101", "Marginal"],
            "7" : ["-99", "Marginal"],
            "8" : ["-97", "Marginal"],
            "9" : ["-95", "Marginal"],
            "10" : ["-93", "OK"],
            "11" : ["-91", "OK"],
            "12" : ["-89", "OK"],
            "13" : ["-87", "OK"],
            "14" : ["-85", "OK"],
            "15" : ["-83", "Good"],
            "16" : ["-81", "Good"],
            "17" : ["-79", "Good"],
            "18" : ["-77", "Good"],
            "19" : ["-75", "Good"],
            "20" : ["-73", "Excellent"],
            "21" : ["-71", "Excellent"],
            "22" : ["-69", "Excellent"],
            "23" : ["-67", "Excellent"],
            "24" : ["-65", "Excellent"],
            "25" : ["-63", "Excellent"],
            "26" : ["-61", "Excellent"],
            "27" : ["-59", "Excellent"],
            "28" : ["-57", "Excellent"],
            "29" : ["-55", "Excellent"],
            "30" : ["-53", "Excellent"],
            "99" : ["Unknown", "Unknown"]
            }

        return RSSILookup.get(Value, ["Unknown", "Unknown"])

    #------------------MyModem::Close-------------------------------------------
    def Close(self):
        try:
            try:
                self.KillThread("SendMessageThread")
            except:
                pass
            try:
                self.SerialDevice.Close()
            except:
                pass
        except Exception as e1:
            self.LogErrorLine("Error Closing Modem: " + str(e1))
Ejemplo n.º 16
0
        sys.exit(1)
    try:
        # Set the signal handler
        signal.signal(signal.SIGINT, signal_handler)

        Threads = {}
        UseCallbacks = False
        DefaultTrigger = GPIO.FALLING
        DefaultPullup = GPIO.PUD_UP
        DefaultBounce = 0

        if os.path.isfile(ConfigFilePath + 'gengpioin.conf'):
            config = MyConfig(filename=ConfigFilePath + 'gengpioin.conf',
                              section='gengpioin',
                              log=log)
            Trigger = config.ReadValue('trigger', default="falling")
            if Trigger.lower() == "rising":
                DefaultTrigger = GPIO.RISING
            elif Trigger.lower() == "both":
                DefaultTrigger = GPIO.BOTH
            else:
                DefaultTrigger = GPIO.FALLING

            ResistorPull = config.ReadValue('resistorpull', default="up")
            if ResistorPull.lower() == "down":
                DefaultPullup = GPIO.PUD_DOWN
            elif ResistorPull.lower() == "off":
                DefaultPullup = GPIO.PUD_OFF
            else:
                DefaultPullup = GPIO.PUD_UP
Ejemplo n.º 17
0
            console.error(HelpStr)
            sys.exit()
        elif opt in ("-a", "--address"):
            address = arg
        elif opt in ("-c", "--configpath"):
            ConfigFilePath = arg
            ConfigFilePath = ConfigFilePath.strip()

    port, loglocation = MySupport.GetGenmonInitInfo(ConfigFilePath, log = console)
    log = SetupLogger("client", loglocation + "gensms.log")

    try:

        config = MyConfig(filename = ConfigFilePath + 'gensms.conf', section = 'gensms', log = log)

        account_sid = config.ReadValue('accountsid', default = "")
        auth_token = config.ReadValue('authtoken', default = "")
        to_number = config.ReadValue('to_number', default = "")
        from_number = config.ReadValue('from_number', default = "")

        if account_sid == "" or auth_token == "" or to_number == "" or from_number == "":
            log.error("Missing parameter in " + ConfigFilePath + "gensms.conf")
            console.error("Missing parameter in " + ConfigFilePath + "gensms.conf")
            sys.exit(1)

    except Exception as e1:
        log.error("Error reading " + ConfigFilePath + "gensms.conf: " + str(e1))
        console.error("Error reading " + ConfigFilePath + "gensms.conf: " + str(e1))
        sys.exit(1)
    try:
        GenNotify = GenNotify(
Ejemplo n.º 18
0
class Loader(MySupport):
    def __init__(self,
                 start=False,
                 stop=False,
                 hardstop=False,
                 loglocation="/var/log/",
                 log=None,
                 localinit=False,
                 ConfigFilePath=None):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop

        if ConfigFilePath == None:
            self.ConfigFilePath = "/etc/"
        else:
            self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = self.ConfigFilePath + self.ConfigFileName

        self.ModulePath = os.path.dirname(os.path.realpath(__file__)) + "/"
        self.ConfPath = os.path.dirname(os.path.realpath(__file__)) + "/conf/"

        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader", loglocation + "genloader.log")
        else:
            self.log = log

        self.console = SetupLogger("genloader_console",
                                   log_file="",
                                   stream=True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " +
                             self.configfile +
                             " Copying file to /etc/ directory.")
                if os.path.isfile(self.ConfPath + self.ConfigFileName):
                    copyfile(self.ConfPath + self.ConfigFileName,
                             self.configfile)
                else:
                    self.LogInfo("Unable to find config file.")
                    sys.exit(2)

            self.config = MyConfig(filename=self.configfile,
                                   section="genmon",
                                   log=self.log)
            if not self.GetConfig():
                self.LogInfo("Error reading config file. Exiting")
                sys.exit(2)

            if not self.ValidateConfig():
                self.LogInfo("Error validating config. Exiting")
                sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name]
            ['flask', 'flask'],
            ['configparser', 'configparser'],
            ['serial', 'pyserial'],
            ['crcmod', 'crcmod'],
            ['pyowm', 'pyowm'],
            ['pytz', 'pytz']
        ]
        try:
            ErrorOccured = False
            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] +
                                 " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1]):
                        self.LogInfo("Error: unable to install library " +
                                     Module[1])
                        ErrorOccured = True
            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self, libraryname):

        try:
            process = Popen(['pip', 'install', libraryname],
                            stdout=PIPE,
                            stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " +
                             libraryname + " : " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname + ": " +
                         str(e1),
                         LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(self.ModulePath +
                                          self.CachedConfig[Module]["module"]):
                        self.LogInfo("Enable to find file " + self.ModulePath +
                                     self.CachedConfig[Module]["module"])
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(
                        self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(
                        ",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(self.ConfigFilePath +
                                              ConfigFile):
                            if os.path.isfile(self.ConfPath + ConfigFile):
                                self.LogInfo("Copying " + ConfigFile + " to " +
                                             self.ConfigFilePath)
                                copyfile(self.ConfPath + ConfigFile,
                                         self.ConfigFilePath + ConfigFile)
                            else:
                                self.LogInfo("Enable to find config file " +
                                             self.ConfPath + ConfigFile)
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False

        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self,
                 section=None,
                 module=None,
                 conffile="",
                 args="",
                 priority='2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section=section)
            self.config.WriteValue('enable', 'False', section=section)
            self.config.WriteValue('hardstop', 'False', section=section)
            self.config.WriteValue('conffile', conffile, section=section)
            self.config.WriteValue('args', args, section=section)
            self.config.WriteValue('priority', priority, section=section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine=True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile',
                                       "gengpioin.conf",
                                       section="gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default="")
                if not len(defValue):
                    self.config.WriteValue('conffile',
                                           "gengpioin.conf",
                                           section="gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine=True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = [
                'genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog',
                'gensms', 'gensms_modem', 'genpushover', 'gensyslog',
                'genmqtt', 'genslack', 'genexercise'
            ]
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genslack.py',
                                      conffile='genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry +
                                      " , adding entry")
                        self.AddEntry(section=entry,
                                      module='genexercise.py',
                                      conffile='genexercise.conf')
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue(
                        'enable', return_type=bool)
                else:
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue(
                        'hardstop', return_type=bool)
                else:
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue(
                        'priority', return_type=int, default=None)
                else:
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue(
                        'postloaddelay', return_type=int, default=0)
                else:
                    TempDict['postloaddelay'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default=None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module][
                            "priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " +
                                 str(e1),
                                 LogLine=True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(),
                                     key=lambda kv: (-kv[1], kv[0])):
                #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine=True)

        return LoadOrder

    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(
                        self.CachedConfig[Module]["module"],
                        HardStop=self.CachedConfig[Module]["hardstop"]):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not self.LoadModule(
                            self.ModulePath +
                            self.CachedConfig[Module]["module"],
                            args=self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module][
                            "postloaddelay"] == None and self.CachedConfig[
                                Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " +
                             str(e1),
                             LogLine=True)
                return False
        return not ErrorOccured

    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, modulename, args=None):
        try:
            self.LogConsole("Starting " + modulename)

            try:
                from subprocess import DEVNULL  # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE
            if args == None:
                # close_fds=True
                pid = subprocess.Popen([sys.executable, modulename],
                                       stdout=OutputStream,
                                       stderr=OutputStream,
                                       stdin=OutputStream)
            else:
                pid = subprocess.Popen([sys.executable, modulename, args],
                                       stdout=OutputStream,
                                       stderr=OutputStream,
                                       stdin=OutputStream)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False

    #---------------------------------------------------------------------------
    def UnloadModule(self, modulename, HardStop=False):
        try:
            self.LogConsole("Stopping " + modulename)
            LoadInfo = []
            LoadInfo.append('pkill')
            if HardStop or self.HardStop:
                LoadInfo.append('-9')
            LoadInfo.append('-u')
            LoadInfo.append('root')
            LoadInfo.append('-f')
            LoadInfo.append(modulename)

            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine=True)
            return False
Ejemplo n.º 19
0
class Monitor(MySupport):

    def __init__(self, ConfigFilePath = ProgramDefaults.ConfPath):
        super(Monitor, self).__init__()

        self.ProgramName = "Generator Monitor"
        self.Version = "Unknown"
        self.log = None
        self.IsStopping = False
        self.ProgramComplete = False
        if ConfigFilePath == None or ConfigFilePath == "":
            self.ConfigFilePath = ProgramDefaults.ConfPath
        else:
            self.ConfigFilePath = ConfigFilePath

        self.ConnectionList = []    # list of incoming connections for heartbeat
        # defautl values
        self.SiteName = "Home"
        self.ServerSocket = None
        self.ServerSocketPort = ProgramDefaults.ServerPort    # server socket for nagios heartbeat and command/status
        self.IncomingEmailFolder = "Generator"
        self.ProcessedEmailFolder = "Generator/Processed"

        self.FeedbackLogFile = self.ConfigFilePath + "feedback.json"
        self.LogLocation = ProgramDefaults.LogPath
        self.LastLogFileSize = 0
        self.NumberOfLogSizeErrors = 0
        # set defaults for optional parameters
        self.NewInstall = False         # True if newly installed or newly upgraded version
        self.FeedbackEnabled = False    # True if sending autoated feedback on missing information
        self.FeedbackMessages = {}
        self.OneTimeMessages = {}
        self.MailInit = False       # set to true once mail is init
        self.CommunicationsActive = False   # Flag to let the heartbeat thread know we are communicating
        self.Controller = None
        self.ControllerSelected = None
        self.bDisablePlatformStats = False
        self.ReadOnlyEmailCommands = False
        self.SlowCPUOptimization = False
        # weather parameters
        self.WeatherAPIKey = None
        self.WeatherLocation = None
        self.UseMetric = False
        self.WeatherMinimum = True
        self.DisableWeather = False
        self.MyWeather = None

        # Time Sync Related Data
        self.bSyncTime = False          # Sync gen to system time
        self.bSyncDST = False           # sync time at DST change
        self.bDST = False               # Daylight Savings Time active if True
        # simulation
        self.Simulation = False
        self.SimulationFile = None

        self.console = SetupLogger("genmon_console", log_file = "", stream = True)

        if os.geteuid() != 0:
            self.LogConsole("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'.")
            sys.exit(1)

        if not os.path.isfile(self.ConfigFilePath + 'genmon.conf'):
            self.LogConsole("Missing config file : " + self.ConfigFilePath + 'genmon.conf')
            sys.exit(1)
        if not os.path.isfile(self.ConfigFilePath + 'mymail.conf'):
            self.LogConsole("Missing config file : " + self.ConfigFilePath + 'mymail.conf')
            sys.exit(1)

        self.config = MyConfig(filename = self.ConfigFilePath + 'genmon.conf', section = "GenMon", log = self.console)
        # read config file
        if not self.GetConfig():
            self.LogConsole("Failure in Monitor GetConfig")
            sys.exit(1)

        # log errors in this module to a file
        self.log = SetupLogger("genmon", self.LogLocation + "genmon.log")

        self.config.log = self.log

        if self.IsLoaded():
            self.LogConsole("ERROR: genmon.py is already loaded.")
            self.LogError("ERROR: genmon.py is already loaded.")
            sys.exit(1)


        if self.NewInstall:
            self.LogError("New version detected: Old = %s, New = %s" % (self.Version, GENMON_VERSION))
            self.Version = GENMON_VERSION

        self.ProgramStartTime = datetime.datetime.now()     # used for com metrics
        self.LastSofwareUpdateCheck = datetime.datetime.now()

        atexit.register(self.Close)
        signal.signal(signal.SIGTERM, self.Close)
        signal.signal(signal.SIGINT, self.Close)

        # start thread to accept incoming sockets for nagios heartbeat and command / status clients
        self.Threads["InterfaceServerThread"] = MyThread(self.InterfaceServerThread, Name = "InterfaceServerThread")

        # init mail, start processing incoming email
        self.mail = MyMail(monitor=True, incoming_folder = self.IncomingEmailFolder,
            processed_folder =self.ProcessedEmailFolder,incoming_callback = self.ProcessCommand,
            loglocation = self.LogLocation, ConfigFilePath = ConfigFilePath)

        self.Threads = self.MergeDicts(self.Threads, self.mail.Threads)
        self.MailInit = True

        self.FeedbackPipe = MyPipe("Feedback", self.FeedbackReceiver,
            log = self.log, ConfigFilePath = self.ConfigFilePath)
        self.Threads = self.MergeDicts(self.Threads, self.FeedbackPipe.Threads)
        self.MessagePipe = MyPipe("Message", self.MessageReceiver, log = self.log,
            nullpipe = self.mail.DisableSNMP, ConfigFilePath = self.ConfigFilePath)
        self.Threads = self.MergeDicts(self.Threads, self.MessagePipe.Threads)

        try:
            #Starting device connection
            if self.Simulation:
                self.LogError("Simulation Running")
            if not self.ControllerSelected == None and len(self.ControllerSelected):
                self.LogError("Selected Controller: " + str(self.ControllerSelected))
            else:
                self.ControllerSelected = "generac_evo_nexus"

            if self.ControllerSelected.lower() == "h_100" :
                self.Controller = HPanel(self.log, newinstall = self.NewInstall, simulation = self.Simulation, simulationfile = self.SimulationFile, message = self.MessagePipe, feedback = self.FeedbackPipe, config = self.config)
            else:
                self.Controller = Evolution(self.log, self.NewInstall, simulation = self.Simulation, simulationfile = self.SimulationFile, message = self.MessagePipe, feedback = self.FeedbackPipe, config = self.config)
            self.Threads = self.MergeDicts(self.Threads, self.Controller.Threads)

        except Exception as e1:
            self.LogErrorLine("Error opening controller device: " + str(e1))
            sys.exit(1)


        self.StartThreads()

        self.ProcessFeedbackInfo()

        # send mail to tell we are starting
        self.MessagePipe.SendMessage("Generator Monitor Starting at " + self.SiteName, "Generator Monitor Starting at " + self.SiteName , msgtype = "info")

        self.LogError("GenMon Loaded for site: " + self.SiteName)

    # ------------------------ Monitor::StartThreads----------------------------
    def StartThreads(self, reload = False):

        try:
            # start thread to accept incoming sockets for nagios heartbeat
            self.Threads["ComWatchDog"] = MyThread(self.ComWatchDog, Name = "ComWatchDog")

            if self.bSyncDST or self.bSyncTime:     # Sync time thread
                self.Threads["TimeSyncThread"] = MyThread(self.TimeSyncThread, Name = "TimeSyncThread")

            if not self.DisableWeather and not self.WeatherAPIKey == None and len(self.WeatherAPIKey) and not self.WeatherLocation == None and len(self.WeatherLocation):
                Unit = 'metric' if self.UseMetric else 'imperial'
                self.MyWeather = MyWeather(self.WeatherAPIKey, location = self.WeatherLocation, unit = Unit, log = self.log)
                self.Threads = self.MergeDicts(self.Threads, self.MyWeather.Threads)
        except Exception as e1:
            self.LogErrorLine("Error in StartThreads: " + str(e1))

    # -------------------- Monitor::GetConfig-----------------------------------
    def GetConfig(self):

        try:
            if self.config.HasOption('sitename'):
                self.SiteName = self.config.ReadValue('sitename')

            if self.config.HasOption('incoming_mail_folder'):
                self.IncomingEmailFolder = self.config.ReadValue('incoming_mail_folder')     # imap folder for incoming mail

            if self.config.HasOption('processed_mail_folder'):
                self.ProcessedEmailFolder = self.config.ReadValue('processed_mail_folder')   # imap folder for processed mail
            #  server_port, must match value in myclient.py and check_monitor_system.py and any calling client apps
            if self.config.HasOption('server_port'):
                self.ServerSocketPort = self.config.ReadValue('server_port', return_type = int)

            self.LogLocation = self.config.ReadValue('loglocation', default = ProgramDefaults.LogPath)

            if self.config.HasOption('syncdst'):
                self.bSyncDST = self.config.ReadValue('syncdst', return_type = bool)
            if self.config.HasOption('synctime'):
                self.bSyncTime = self.config.ReadValue('synctime', return_type = bool)

            if self.config.HasOption('disableplatformstats'):
                self.bDisablePlatformStats = self.config.ReadValue('disableplatformstats', return_type = bool)

            if self.config.HasOption('simulation'):
                self.Simulation = self.config.ReadValue('simulation', return_type = bool)

            if self.config.HasOption('simulationfile'):
                self.SimulationFile = self.config.ReadValue('simulationfile')

            if self.config.HasOption('controllertype'):
                self.ControllerSelected = self.config.ReadValue('controllertype')

            if self.config.HasOption('disableweather'):
                self.DisableWeather = self.config.ReadValue('disableweather', return_type = bool)
            else:
                self.DisableWeather = False

            if self.config.HasOption('weatherkey'):
                self.WeatherAPIKey = self.config.ReadValue('weatherkey')

            if self.config.HasOption('weatherlocation'):
                self.WeatherLocation = self.config.ReadValue('weatherlocation')

            if self.config.HasOption('metricweather'):
                self.UseMetric = self.config.ReadValue('metricweather', return_type = bool)

            if self.config.HasOption('minimumweatherinfo'):
                self.WeatherMinimum = self.config.ReadValue('minimumweatherinfo', return_type = bool)

            if self.config.HasOption('readonlyemailcommands'):
                self.ReadOnlyEmailCommands = self.config.ReadValue('readonlyemailcommands', return_type = bool)

            if self.config.HasOption('optimizeforslowercpu'):
                self.SlowCPUOptimization = self.config.ReadValue('optimizeforslowercpu', return_type = bool)

            if self.config.HasOption('version'):
                self.Version = self.config.ReadValue('version')
                if not self.Version == GENMON_VERSION:
                    self.config.WriteValue('version', GENMON_VERSION)
                    self.NewInstall = True
            else:
                self.config.WriteValue('version', GENMON_VERSION)
                self.NewInstall = True
                self.Version = GENMON_VERSION
            if self.config.HasOption("autofeedback"):
                self.FeedbackEnabled = self.config.ReadValue('autofeedback', return_type = bool)
            else:
                self.config.WriteValue('autofeedback', "False")
                self.FeedbackEnabled = False
            # Load saved feedback log if log is present
            if os.path.isfile(self.FeedbackLogFile):
                try:
                    with open(self.FeedbackLogFile) as infile:
                        self.FeedbackMessages = json.load(infile)
                except Exception as e1:
                    os.remove(self.FeedbackLogFile)

            self.UpdateCheck = self.config.ReadValue('update_check', return_type = bool, default = True)
            self.UserURL = self.config.ReadValue('user_url',  default = "").strip()

        except Exception as e1:
            self.Console("Missing config file or config file entries (genmon): " + str(e1))
            return False

        return True

    #---------------------------------------------------------------------------
    def ProcessFeedbackInfo(self):

        try:
            if self.FeedbackEnabled:
                for Key, Entry in self.FeedbackMessages.items():
                    self.MessagePipe.SendMessage("Generator Monitor Submission", Entry , recipient = self.MaintainerAddress, files = self.GetLogFileNames(), msgtype = "error")
                # delete unsent Messages
                if os.path.isfile(self.FeedbackLogFile):
                    os.remove(self.FeedbackLogFile)
        except Exception as e1:
            self.LogErrorLine("Error in ProcessFeedbackInfo: " + str(e1))

    #---------------------------------------------------------------------------
    def FeedbackReceiver(self, Message):

        try:
            FeedbackDict = {}
            FeedbackDict = json.loads(Message)
            self.SendFeedbackInfo(FeedbackDict["Reason"],
                Always = FeedbackDict["Always"], Message = FeedbackDict["Message"],
                FullLogs = FeedbackDict["FullLogs"], NoCheck = FeedbackDict["NoCheck"])

        except Exception as e1:
            self.LogErrorLine("Error in  FeedbackReceiver: " + str(e1))
            self.LogError("Size : " + str(len(Message)))
            self.LogError("Message : " + str(Message))
    #---------------------------------------------------------------------------
    def MessageReceiver(self, Message):

        try:
            MessageDict = {}
            MessageDict = json.loads(Message)

            if MessageDict["onlyonce"]:
                Subject = self.OneTimeMessages.get(MessageDict["subjectstr"], None)
                if Subject == None:
                    self.OneTimeMessages[MessageDict["subjectstr"]] = MessageDict["msgstr"]
                else:
                    return

            self.mail.sendEmail(MessageDict["subjectstr"],
                MessageDict["msgstr"], recipient = MessageDict["recipient"],
                files = MessageDict["files"], deletefile= MessageDict["deletefile"],
                msgtype= MessageDict["msgtype"])

        except Exception as e1:
            self.LogErrorLine("Error in  MessageReceiver: " + str(e1))
    #---------------------------------------------------------------------------
    def SendFeedbackInfo(self, Reason, Always = False, Message = None, FullLogs = True, NoCheck = False):
        try:
            if self.NewInstall or Always:

                CheckedSent = self.FeedbackMessages.get(Reason, "")

                if not CheckedSent == "" and not NoCheck:
                    return

                if not NoCheck:
                    self.LogError(Reason + " : " + Message)

                msgbody = "Reason = " + Reason + "\n"
                if Message != None:
                    msgbody += "Message : " + Message + "\n"
                msgbody += self.printToString(self.ProcessDispatch(self.GetStartInfo(NoTile = True),""))
                if not self.bDisablePlatformStats:
                    msgbody += self.printToString(self.ProcessDispatch({"Platform Stats" : self.GetPlatformStats()},""))
                msgbody += self.Controller.DisplayRegisters(AllRegs = FullLogs)

                msgbody += "\n" + self.GetSupportData() + "\n"
                if self.FeedbackEnabled:
                    self.MessagePipe.SendMessage("Generator Monitor Submission", msgbody , recipient = self.MaintainerAddress, files = self.GetLogFileNames(), msgtype = "error")

                self.FeedbackMessages[Reason] = msgbody
                # if feedback not enabled, save the log to file
                if not self.FeedbackEnabled:
                    with open(self.FeedbackLogFile, 'w') as outfile:
                        json.dump(self.FeedbackMessages, outfile, sort_keys = True, indent = 4, ensure_ascii = False)
        except Exception as e1:
            self.LogErrorLine("Error in SendFeedbackInfo: " + str(e1))

    #---------- Monitor::EmailSendIsEnabled-------------------------------------
    def EmailSendIsEnabled(self):

        EmailThread = self.Threads.get("SendMailThread",None)
        if EmailThread == None:
            return False
        return True

    #---------- Monitor::GetSupportData-----------------------------------------
    def GetSupportData(self):

        SupportData = collections.OrderedDict()
        SupportData["Program Run Time"] = self.GetProgramRunTime()
        SupportData["Monitor Health"] = self.GetSystemHealth()
        SupportData["StartInfo"] = self.GetStartInfo(NoTile = True)
        if not self.bDisablePlatformStats:
            SupportData["PlatformStats"] = self.GetPlatformStats()
        SupportData["Data"] = self.Controller.DisplayRegisters(AllRegs = True, DictOut = True)
        # Raw Modbus data
        SupportData["Registers"] = self.Controller.Registers
        SupportData["Strings"] = self.Controller.Strings
        SupportData["FileData"] = self.Controller.FileData

        return json.dumps(SupportData, sort_keys=False)

    #---------- Monitor::GetLogFileNames----------------------------------------
    def GetLogFileNames(self):

        try:
            LogList = []
            FilesToSend = ["genmon.log", "genserv.log", "mymail.log", "myserial.log",
                "mymodbus.log", "gengpio.log", "gengpioin.log", "gensms.log",
                "gensms_modem.log", "genmqtt.log", "genpushover.log", "gensyslog.log",
                "genloader.log", "myserialtcp.log", "genlog.log", "genslack.log",
                "genexercise.log","genemail2sms.log", "gentankutil.log", "genalexa.log",
                "gensnmp.log"]
            for File in FilesToSend:
                LogFile = self.LogLocation + File
                if os.path.isfile(LogFile):
                    LogList.append(LogFile)
            return LogList
        except Exception as e1:
            return None

    #---------- Monitor::SendSupportInfo----------------------------------------
    def SendSupportInfo(self, SendLogs = True):

        try:
            if not self.EmailSendIsEnabled():
                self.LogError("Error in SendSupportInfo: send email is not enabled")
                return "Send Email is not enabled."

            msgbody = ""
            msgbody += self.printToString(self.ProcessDispatch(self.GetStartInfo(NoTile = True),""))
            if not self.bDisablePlatformStats:
                msgbody += self.printToString(self.ProcessDispatch({"Platform Stats" : self.GetPlatformStats()},""))

            msgbody += self.Controller.DisplayRegisters(AllRegs = True)

            msgbody += "\n" + self.GetSupportData()  + "\n"
            msgtitle = "Generator Monitor Log File Submission"
            if SendLogs == True:
                LogList = self.GetLogFileNames()
            else:
                msgtitle = "Generator Monitor Register Submission"
                LogList = None
            self.MessagePipe.SendMessage(msgtitle, msgbody , recipient = self.MaintainerAddress, files = LogList, msgtype = "error")
            return "Log files submitted"
        except Exception as e1:
            self.LogErrorLine("Error in SendSupportInfo: " + str(e1))

    #---------- process command from email and socket --------------------------
    def ProcessCommand(self, command, fromsocket = False):

        LocalError = False
        command = command.decode('utf-8')
        msgsubject = "Generator Command Response at " + self.SiteName
        if not fromsocket:
            msgbody = "\n"
        else:
            msgbody = ""

        if(len(command)) == 0:
            msgsubject = "Error in Generator Command (Lenght is zero)"
            msgbody += "Invalid GENERATOR command: zero length command."
            LocalError = True

        if not LocalError:
            if(not command.lower().startswith( 'generator:' )):
                msgsubject = "Error in Generator Command (command prefix)"
                msgbody += "Invalid GENERATOR command: all commands must be prefixed by \"generator: \""
                LocalError = True

        if LocalError:
            if not fromsocket:
                self.MessagePipe.SendMessage(msgsubject, msgbody, msgtype = "error")
                return ""       # ignored by email module
            else:
                msgbody += "EndOfMessage"
                return msgbody

        if command.lower().startswith('generator:'):
            command = command[len('generator:'):]

        CommandDict = {
            "registers"     : [self.Controller.DisplayRegisters,(False,), False],         # display registers
            "allregs"       : [self.Controller.DisplayRegisters, (True,), False],         # display registers
            "logs"          : [self.Controller.DisplayLogs, (True, False), False],
            "status"        : [self.Controller.DisplayStatus, (), False],                 # display decoded generator info
            "maint"         : [self.Controller.DisplayMaintenance, (), False],
            "monitor"       : [self.DisplayMonitor, (), False],
            "outage"        : [self.Controller.DisplayOutage, (), False],
            "settime"       : [self.StartTimeThread, (), False],                  # set time and date
            "setexercise"   : [self.Controller.SetGeneratorExerciseTime, (command.lower(),), False],
            "setquiet"      : [self.Controller.SetGeneratorQuietMode, ( command.lower(),), False],
            "setremote"     : [self.Controller.SetGeneratorRemoteCommand, (command.lower(),), False],
            "testcommand"   : [self.Controller.TestCommand, (command.lower(),), False],
            "network_status": [self.InternetConnected, (), False],
            "help"          : [self.DisplayHelp, (), False],                   # display help screen
            ## These commands are used by the web / socket interface only
            "power_log_json"    : [self.Controller.GetPowerHistory, (command.lower(),), True],
            "power_log_clear"   : [self.Controller.ClearPowerLog, (), True],
            "start_info_json"   : [self.GetStartInfo, (), True],
            "registers_json"    : [self.Controller.DisplayRegisters, (False, True), True],  # display registers
            "allregs_json"      : [self.Controller.DisplayRegisters, (True, True), True],   # display registers
            "logs_json"         : [self.Controller.DisplayLogs, (True, True), True],
            "status_json"       : [self.Controller.DisplayStatus, (True,), True],
            "status_num_json"   : [self.Controller.DisplayStatus, (True,True), True],
            "maint_json"        : [self.Controller.DisplayMaintenance, (True,), True],
            "maint_num_json"    : [self.Controller.DisplayMaintenance, (True,True), True],
            "monitor_json"      : [self.DisplayMonitor, (True,), True],
            "monitor_num_json"  : [self.DisplayMonitor, (True,True), True],
            "weather_json"      : [self.DisplayWeather, (True,), True],
            "outage_json"       : [self.Controller.DisplayOutage, (True,), True],
            "outage_num_json"   : [self.Controller.DisplayOutage, (True,True), True],
            "gui_status_json"   : [self.GetStatusForGUI, (), True],
            "get_maint_log_json": [self.Controller.GetMaintLog, (), True],
            "add_maint_log"     : [self.Controller.AddEntryToMaintLog, (command,), True],    # Do not do command.lower() since this input is JSON
            "clear_maint_log"   : [self.Controller.ClearMaintLog, (), True],
            "getsitename"       : [self.GetSiteName, (), True],
            "getbase"           : [self.Controller.GetBaseStatus, (), True],    #  (UI changes color based on exercise, running , ready status)
            "gethealth"         : [self.GetSystemHealth, (), True],
            "getregvalue"       : [self.Controller.GetRegValue, (command.lower(),), True],     # only used for debug purposes, read a cached register value
            "readregvalue"      : [self.Controller.ReadRegValue, (command.lower(),), True],    # only used for debug purposes, Read Register Non Cached
            "getdebug"          : [self.GetDeadThreadName, (), True],           # only used for debug purposes. If a thread crashes it tells you the thread name
            "sendregisters"     : [self.SendSupportInfo, (False,), True],
            "sendlogfiles"      : [self.SendSupportInfo, (True,), True],
            "set_tank_data"     : [self.Controller.SetExternalTankData, (command,), True]
        }

        CommandList = command.split(' ')

        ValidCommand = False
        try:
            for item in CommandList:
                if not len(item):
                    continue
                item = item.strip()
                LookUp = item
                if "=" in item:
                    BaseCmd = item.split('=')
                    LookUp = BaseCmd[0]
                # check if we disallow write commands via email
                if self.ReadOnlyEmailCommands and not fromsocket and LookUp in ["settime", "setexercise", "setquiet", "setremote"]:
                    continue

                ExecList = CommandDict.get(LookUp.lower(),None)
                if ExecList == None:
                    continue
                if ExecList[0] == None:
                    continue
                if not fromsocket and ExecList[2]:
                    continue
                # Execut Command
                ReturnMessage = ExecList[0](*ExecList[1])

                ValidCommand = True

                if LookUp.lower().endswith("_json") and not isinstance(ReturnMessage, str):
                    msgbody += json.dumps(ReturnMessage, sort_keys=False)
                else:
                    msgbody += ReturnMessage

                if not fromsocket:
                    msgbody += "\n"
        except Exception as e1:
            self.LogErrorLine("Error Processing Commands: " + command + ": "+ str(e1))

        if not ValidCommand:
            msgbody += "No valid command recognized."
        if not fromsocket:
            self.MessagePipe.SendMessage(msgsubject, msgbody, msgtype = "warn")
            return ""       # ignored by email module
        else:
            msgbody += "EndOfMessage"
            return msgbody

    #------------ Monitor::DisplayHelp -----------------------------------------
    def DisplayHelp(self):

        outstring = ""
        outstring += "Help:\n"
        outstring += self.printToString("\nCommands:")
        outstring += self.printToString("   status      - display engine and line information")
        outstring += self.printToString("   maint       - display maintenance and service information")
        outstring += self.printToString("   outage      - display current and last outage (since program launched)")
        outstring += self.printToString("                       info, also shows utility min and max values")
        outstring += self.printToString("   monitor     - display communication statistics and monitor health")
        outstring += self.printToString("   logs        - display all alarm, on/off, and maintenance logs")
        outstring += self.printToString("   registers   - display contents of registers being monitored")
        outstring += self.printToString("   settime     - set generator time to system time")
        outstring += self.printToString("   setexercise - set the exercise time of the generator. ")
        outstring += self.printToString("                      i.e. setexercise=Monday,13:30,Weekly")
        outstring += self.printToString("                   if Enhanced Exercise Frequency is supported by your generator:")
        outstring += self.printToString("                      i.e. setexercise=Monday,13:30,BiWeekly")
        outstring += self.printToString("                      i.e. setexercise=15,13:30,Monthly")
        outstring += self.printToString("   setquiet    - enable or disable exercise quiet mode, ")
        outstring += self.printToString("                      i.e.  setquiet=on or setquiet=off")
        outstring += self.printToString("   setremote   - issue remote command. format is setremote=command, ")
        outstring += self.printToString("                      where command is start, stop, starttransfer,")
        outstring += self.printToString("                      startexercise. i.e. setremote=start")
        outstring += self.printToString("   help        - Display help on commands")
        outstring += self.printToString("\n")

        outstring += self.printToString("To clear the Alarm/Warning message, press OFF on the control panel keypad")
        outstring += self.printToString("followed by the ENTER key. To access Dealer Menu on the Evolution")
        outstring += self.printToString("controller, from the top menu selection (SYSTEM, DATE/TIME,BATTERY, SUB-MENUS)")
        outstring += self.printToString("enter UP UP ESC DOWN UP ESC UP, then go to the dealer menu and press enter.")
        outstring += self.printToString("For liquid cooled models a level 2 dealer code can be entered, ESC UP UP DOWN")
        outstring += self.printToString("DOWN ESC ESC, then navigate to the dealer menu and press enter.")
        outstring += self.printToString("Passcode for Nexus controller is ESC, UP, UP ESC, DOWN, UP, ESC, UP, UP, ENTER.")
        outstring += self.printToString("\n")

        return outstring

    #------------ Monitor::GetProgramRunTime -----------------------------------
    def GetProgramRunTime(self):
        try:
            ProgramRunTime = datetime.datetime.now() - self.ProgramStartTime
            outstr = str(ProgramRunTime).split(".")[0]  # remove microseconds from string
            return self.ProgramName + " running for " + outstr + "."
        except Exception as e1:
            self.LogErrorLine("Error in GetProgramRunTime:" + str(e1))
            return "Unknown"
    #------------ Monitor::GetWeatherData --------------------------------------
    def GetWeatherData(self, ForUI = False):

        if self.MyWeather == None:
            return None

        ReturnData = self.MyWeather.GetWeather(minimum = self.WeatherMinimum, ForUI = ForUI)

        if not len(ReturnData):
            return None
        return ReturnData

    #------------ Monitor::GetUserDefinedData ----------------------------------
    # this assumes one json object, the file can be formatted (i.e. on multiple
    # lines) or can be on a single line
    def GetUserDefinedData(self):

        try:
            FileName = os.path.dirname(os.path.realpath(__file__)) + "/userdefined.json"

            if not os.path.isfile(FileName):
                return None

            if os.path.getsize(FileName) == 0:
                return None

            with open(FileName) as f:
                data = json.load(f,object_pairs_hook=collections.OrderedDict)
            return data
        except Exception as e1:
            self.LogErrorLine("Error in GetUserDefinedData: " + str(e1))
        return None

    #------------ Monitor::DisplayWeather --------------------------------------
    def DisplayWeather(self, DictOut = False):

        WeatherData = collections.OrderedDict()

        try:
            ReturnData = self.GetWeatherData()
            if not ReturnData == None and len(ReturnData):
                WeatherData["Weather"] = ReturnData

            if not DictOut:
                return self.printToString(self.ProcessDispatch(WeatherData,""))
        except Exception as e1:
            self.LogErrorLine("Error in DisplayWeather: " + str(e1))

        return WeatherData

    #------------ Monitor::DisplayMonitor --------------------------------------
    def DisplayMonitor(self, DictOut = False, JSONNum = False):

        try:
            Monitor = collections.OrderedDict()
            MonitorData = []
            Monitor["Monitor"] = MonitorData
            GenMonStats = []
            SerialStats = []
            MonitorData.append({"Generator Monitor Stats" : GenMonStats})
            MonitorData.append({"Communication Stats" : self.Controller.GetCommStatus()})

            GenMonStats.append({"Monitor Health" :  self.GetSystemHealth()})
            GenMonStats.append({"Controller" : self.Controller.GetController(Actual = False)})

            GenMonStats.append({"Run time" : self.GetProgramRunTime()})
            if self.Controller.PowerMeterIsSupported():
                GenMonStats.append({"Power log file size" : self.Controller.GetPowerLogFileDetails()})
            GenMonStats.append({"Generator Monitor Version" : GENMON_VERSION})

            if not self.bDisablePlatformStats:
                PlatformStats = self.GetPlatformStats()
                if not PlatformStats == None:
                    MonitorData.append({"Platform Stats" : PlatformStats})

            WeatherData = self.GetWeatherData()
            if not WeatherData == None and len(WeatherData):
                MonitorData.append({"Weather" : WeatherData})

            UserData = self.GetUserDefinedData()
            if not UserData == None and len(UserData):
                MonitorData.append({"External Data" : UserData})

            if not DictOut:
                return self.printToString(self.ProcessDispatch(Monitor,""))
        except Exception as e1:
            self.LogErrorLine("Error in DisplayMonitor: " + str(e1))
        return Monitor

    #------------ Monitor::GetStartInfo-----------------------------------------
    def GetStartInfo(self, NoTile = False):

        StartInfo = collections.OrderedDict()
        StartInfo["version"] = GENMON_VERSION
        StartInfo["sitename"] = self.SiteName
        ControllerStartInfo = self.Controller.GetStartInfo(NoTile = NoTile)
        StartInfo = self.MergeDicts(StartInfo, ControllerStartInfo)
        return StartInfo

    #------------ Monitor::GetStatusForGUI -------------------------------------
    def GetStatusForGUI(self):

        Status = {}

        Status["SystemHealth"] = self.GetSystemHealth()
        Status["UnsentFeedback"] = str(os.path.isfile(self.FeedbackLogFile))

        if not self.bDisablePlatformStats:
            PlatformStats = self.GetPlatformStats(usemetric = True)
            if not PlatformStats == None and len(PlatformStats):
                Status["PlatformStats"] = PlatformStats
        WeatherData = self.GetWeatherData(ForUI = True)
        if not WeatherData == None and len(WeatherData):
            Status["Weather"] = WeatherData
        # Monitor Time
        Status["MonitorTime"] = datetime.datetime.now().strftime("%m/%d/%Y %H:%M")
        # Engine run hours
        Status["RunHours"] = self.Controller.GetRunHours()
        ReturnDict = self.MergeDicts(Status, self.Controller.GetStatusForGUI())

        return ReturnDict

    #-------------Monitor::GetSystemHealth--------------------------------------
    #   returns the health of the monitor program
    def GetSystemHealth(self):

        outstr = ""
        if not self.Controller.InitComplete:
            outstr += "System Initializing. "
        if not self.AreThreadsAlive():
            outstr += " Threads are dead. "
        if  not self.CommunicationsActive:
            outstr += " Not receiving data. "
        if not self.LogFileIsOK():
            outstr += " Log file is reporting errors."

        if len(outstr) == 0:
            outstr = "OK"
        return outstr

    #----------  Monitor::StartTimeThread---------------------------------------
    def StartTimeThread(self):

        # This is done is a separate thread as not to block any return email processing
        # since we attempt to sync with generator time
        MyThread(self.Controller.SetGeneratorTimeDate, Name = "SetTimeThread")
        return "Time Set: Command Sent\n"

    #----------  Monitor::TimeSyncThread----------------------------------------
    def TimeSyncThread(self):

        self.bDST = self.is_dst()   # set initial DST state

        time.sleep(0.25)
        while True:
            if self.WaitForExit("TimeSyncThread", 1):  # ten min
                return
            if self.Controller.InitComplete:
                break

        # if we are not always syncing, then set the time once
        if not self.bSyncTime:
            self.StartTimeThread()

        while True:

            if self.bSyncDST:
                if self.bDST != self.is_dst():  # has DST changed?
                    self.bDST = self.is_dst()   # update Flag
                    # time changed so some comm stats may be off
                    self.Controller.ResetCommStats()
                    # set new time
                    self.StartTimeThread()           # start settime thread
                    self.MessagePipe.SendMessage("Generator Time Update at " + self.SiteName, "Time updated due to daylight savings time change", msgtype = "info")

            if self.bSyncTime:
                # update gen time
                self.StartTimeThread()

            if self.WaitForExit("TimeSyncThread", 60 * 60):  # 1 hour
                return


    #----------  Monitor::is_dst------------------------------------------------
    def is_dst(self):
        #Determine whether or not Daylight Savings Time (DST) is currently in effect
        t = time.localtime()
        isdst = t.tm_isdst
        return (isdst != 0)

    #----------  Monitor::ComWatchDog-------------------------------------------
    #----------  monitors receive data status to make sure we are still communicating
    def ComWatchDog(self):

        self.CommunicationsActive = False
        time.sleep(0.25)

        NoticeSent = False
        LastActiveTime = datetime.datetime.now()
        while True:
            if self.WaitForExit("ComWatchDog", 1):
                return
            if self.Controller.InitComplete:
                break

        if self.Controller.ModBus.UseTCP:
            WatchDogPollTime = 8
        else:
            WatchDogPollTime = 2

        while True:
            try:
                # check for software update
                self.CheckSoftwareUpdate()
                self.CommunicationsActive = self.Controller.ComminicationsIsActive()

                if self.CommunicationsActive:
                    LastActiveTime = datetime.datetime.now()
                    if NoticeSent:
                        NoticeSent = False
                        self.MessagePipe.SendMessage("Generator Monitor Communication Restored at " + self.SiteName, "Generator Monitor communications with the controller has been restored at " + self.SiteName , msgtype = "info")
                else:
                    if self.GetDeltaTimeMinutes(datetime.datetime.now() - LastActiveTime) > 1 :
                        if not NoticeSent:
                            NoticeSent = True
                            self.MessagePipe.SendMessage("Generator Monitor Communication WARNING at " + self.SiteName, "Generator Monitor is not communicating with the controller at " + self.SiteName , msgtype = "error")

            except Exception as e1:
                self.LogErrorLine("Error in ComWatchDog: " + str(e1))

            if self.WaitForExit("ComWatchDog", WatchDogPollTime):
                return
    #---------- Monitor::CheckSoftwareUpdate------------------------------------
    def CheckSoftwareUpdate(self):

        if not self.UpdateCheck:
            return
        try:
            if self.GetDeltaTimeMinutes(datetime.datetime.now() - self.LastSofwareUpdateCheck) > 1440 :     # check every day
                self.LastSofwareUpdateCheck = datetime.datetime.now()
                # Do the check
                try:
                    import urllib2
                    url = "https://raw.githubusercontent.com/jgyates/genmon/master/genmon.py"
                    data = urllib2.urlopen(url).read(20000) # read only 2000 chars
                    data = data.split("\n") # then split it into lines

                    for line in data:

                        if 'GENMON_VERSION = "V' in line:
                            import re
                            quoted = re.compile('"([^"]*)"')
                            for value in quoted.findall(line):
                                if value != GENMON_VERSION:
                                    # Update Available
                                    title = self.ProgramName + " Software Update " + value + " is available for site " + self.SiteName
                                    msgbody = "\nA software update is available for the " + self.ProgramName + ". The new version (" + value + ") can be updated on the About page of the web interface. You can disable this email from being sent on the Settings page."
                                    if len(self.UserURL):
                                        msgbody += "\n\nWeb Interface URL: " + self.UserURL
                                    msgbody += "\n\nChange Log: https://raw.githubusercontent.com/jgyates/genmon/master/changelog.md"
                                    self.MessagePipe.SendMessage(title , msgbody, msgtype = "info", onlyonce = True)

                except Exception as e1:
                    self.LogErrorLine("Error checking for software update: " + str(e1))

        except Exception as e1:
            self.LogErrorLine("Error in CheckSoftwareUpdate: " + str(e1))

    #---------- Monitor::LogFileIsOK--------------------------------------------
    def LogFileIsOK(self):

        try:
            if not self.Controller.InitComplete:
                return True

            LogFile = self.LogLocation + "genmon.log"

            LogFileSize = os.path.getsize(LogFile)
            if LogFileSize <= self.LastLogFileSize:     # log is unchanged or has rotated
                self.LastLogFileSize = LogFileSize
                self.NumberOfLogSizeErrors = 0
                return True

            LogFileSizeDiff = LogFileSize - self.LastLogFileSize
            self.LastLogFileSize = LogFileSize
            if LogFileSizeDiff >= 100:
                self.NumberOfLogSizeErrors += 1
                if self.NumberOfLogSizeErrors > 3:
                    return False
            else:
                self.NumberOfLogSizeErrors = 0
            return True
        except Exception as e1:
            self.LogErrorLine("Error in LogFileIsOK: " + str(e1))
        return True

    #----------  Monitor::SocketWorkThread-------------------------------------
    #  This thread spawns for each connection established by a client
    #  in InterfaceServerThread
    def SocketWorkThread(self, conn):

        try:

            statusstr = ""
            if self.Controller == None:
                outstr = "WARNING: System Initializing"
                conn.sendall(outstr.encode())
            else:
                if self.Controller.SystemInAlarm():
                    statusstr += "CRITICAL: System in alarm! "
                HealthStr = self.GetSystemHealth()
                if HealthStr != "OK":
                    statusstr += "WARNING: " + HealthStr
                if statusstr == "":
                    statusstr = "OK "

                outstr = statusstr + ": "+ self.Controller.GetOneLineStatus()
                conn.sendall(outstr.encode())

            while True:
                try:
                    data = conn.recv(1024)
                    if len(data):
                        if self.Controller == None:
                            outstr = "Retry, System Initializing"
                        else:
                            outstr = self.ProcessCommand(data, True)
                        conn.sendall(outstr.encode("utf-8"))
                    else:
                        # socket closed remotely
                        break
                except socket.timeout:
                    if self.IsStopping:
                        break
                    continue
                except socket.error as msg:
                    try:
                        self.ConnectionList.remove(conn)
                        conn.close()
                    except:
                        pass
                    break

        except socket.error as msg:
            self.LogError("Error in SocketWorkThread: " + str(msg))
            pass

        try:
            self.ConnectionList.remove(conn)
            conn.close()
        except:
            pass
        # end SocketWorkThread

    #----------  interface for heartbeat server thread -------------------------
    def InterfaceServerThread(self):

        #create an INET, STREAMing socket
        self.ServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # set some socket options so we can resuse the port
        self.ServerSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.ServerSocket.settimeout(.5)
        #bind the socket to a host, and a port
        self.ServerSocket.bind(('', self.ServerSocketPort))
        #become a server socket
        self.ServerSocket.listen(5)

        #wait to accept a connection - blocking call
        while True:
            try:
                conn, addr = self.ServerSocket.accept()
                #self.LogError('Connected with ' + addr[0] + ':' + str(addr[1]))
                conn.settimeout(0.5)
                self.ConnectionList.append(conn)
                SocketThread = threading.Thread(target=self.SocketWorkThread, args = (conn,), name = "SocketWorkThread")
                SocketThread.daemon = True
                SocketThread.start()       # start server thread
            except socket.timeout:
                if self.IsStopping:
                    break
                continue
            except Exception as e1:
                if self.IsStopping:
                    break
                self.LogErrorLine("Exception in InterfaceServerThread" + str(e1))
                if self.WaitForExit("InterfaceServerThread", 0.5 ):
                    break
                continue

        if self.ServerSocket != None:
            if len(self.ConnectionList):
                try:
                    self.ServerSocket.shutdown(socket.SHUT_RDWR)
                except:
                    pass
            self.ServerSocket.close()
            self.ServerSocket = None
        #

    #---------------------Monitor::Close----------------------------------------
    def Close(self):

        # we dont really care about the errors that may be generated on shutdown
        try:
            self.IsStopping = True

            try:
                if self.MyWeather != None:
                    self.MyWeather.Close()
            except:
                pass

            try:
                if self.bSyncDST or self.bSyncTime:
                    self.KillThread("TimeSyncThread")
            except:
                pass

            try:
                self.KillThread("ComWatchDog")
            except:
                pass

            try:
                if not self.Controller == None:
                    self.Controller.Close()
            except:
                pass

            #
            try:
                self.mail.Close()
            except:
                pass
            try:
                for item in self.ConnectionList:
                    try:
                        item.close()
                    except:
                        continue
                    self.ConnectionList.remove(item)
            except:
                pass

            try:
                if(self.ServerSocket != None):
                    self.ServerSocket.shutdown(socket.SHUT_RDWR)
                    self.ServerSocket.close()
                self.KillThread("InterfaceServerThread")
            except:
                pass

            try:
                self.FeedbackPipe.Close()
            except:
                pass
            try:
                self.MessagePipe.Close()
            except:
                pass

            # Tell any remaining threads to stop
            for name, object in self.Threads.items():
                try:
                    if self.Threads[name].IsAlive():
                        self.Threads[name].Stop()
                except Exception as e1:
                    self.LogErrorLine("Error killing thread in Monitor Close: " + name + ":" + str(e1))

        except Exception as e1:
            self.LogErrorLine("Error Closing Monitor: " + str(e1))

        with self.CriticalLock:
            self.LogError("Generator Monitor Shutdown")

        try:

            self.ProgramComplete = True
            sys.exit(0)
        except:
            pass
Ejemplo n.º 20
0
    console, ConfigFilePath, address, port, loglocation, log = MySupport.SetupAddOnProgram(
        "genpushover")

    # Set the signal handler
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)

    try:

        config = MyConfig(filename=os.path.join(ConfigFilePath,
                                                'genpushover.conf'),
                          section='genpushover',
                          log=log)

        appid = config.ReadValue('appid', default=None)
        userid = config.ReadValue('userid', default=None)
        pushsound = config.ReadValue('pushsound', default='updown')

        if appid == None or not len(appid):
            log.error("Error:  invalid app ID")
            console.error("Error:  invalid app ID")
            sys.exit(2)

        if userid == None or not len(userid):
            log.error("Error:  invalid user ID")
            console.error("Error:  invalid user ID")
            sys.exit(2)

    except Exception as e1:
        log.error("Error reading " +
Ejemplo n.º 21
0
    def __init__(self,
        log = None,
        loglocation = ProgramDefaults.LogPath,
        host = ProgramDefaults.LocalHost,
        port = ProgramDefaults.ServerPort,
        configfilepath = ProgramDefaults.ConfPath):

        super(MyMQTT, self).__init__()

        self.LogFileName = loglocation + "genmqtt.log"

        if log != None:
            self.log = log
        else:
            # log errors in this module to a file
            self.log = SetupLogger("client", self.LogFileName)

        # cleanup
        # test
        self.console = SetupLogger("mymqtt_console", log_file = "", stream = True)

        self.Username = None
        self.Password = None
        self.Topic = None

        self.MQTTAddress = None
        self.MonitorAddress = host
        self.MQTTPort = 1883
        self.Topic = "generator"
        self.TopicRoot = None
        self.BlackList = None
        self.UseNumeric = False
        self.PollTime = 2
        self.FlushInterval = float('inf')   # default to inifite flush interval (e.g., never)
        self.Debug = False

        try:
            config = MyConfig(filename =  configfilepath + 'genmqtt.conf', section = 'genmqtt', log = log)

            self.Username = config.ReadValue('username')

            self.Password = config.ReadValue('password')

            self.MQTTAddress = config.ReadValue('mqtt_address')

            if self.MQTTAddress == None or not len(self.MQTTAddress):
                log.error("Error: invalid MQTT server address")
                console.error("Error: invalid MQTT server address")
                sys.exit(1)

            self.MonitorAddress = config.ReadValue('monitor_address', default = self.MonitorAddress)
            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

            self.MQTTPort = config.ReadValue('mqtt_port', return_type = int, default = 1883)

            self.PollTime = config.ReadValue('poll_interval', return_type = float, default = 2.0)

            self.UseNumeric = config.ReadValue('numeric_json', return_type = bool, default = False)

            self.TopicRoot = config.ReadValue('root_topic')

            #http://www.steves-internet-guide.com/mosquitto-tls/
            self.CertificateAuthorityPath =  config.ReadValue('cert_authority_path', default = "")
            self.TLSVersion = config.ReadValue('tls_version', return_type = str, default = "1.0")
            self.CertReqs = config.ReadValue('cert_reqs', return_type = str, default = "Required")

            BlackList = config.ReadValue('blacklist')

            if BlackList != None:
                if len(BlackList):
                    BList = BlackList.strip().split(",")
                    if len(BList):
                        self.BlackList = []
                        for Items in BList:
                            self.BlackList.append(Items.strip())

            self.Debug = config.ReadValue('debug', return_type = bool, default = False)

            if config.HasOption('flush_interval'):
                self.FlushInterval = config.ReadValue('flush_interval', return_type = float, default = float('inf'))
                if self.FlushInterval == 0:
                    self.FlushInterval = float('inf')
            else:
                self.FlushInterval = float('inf')
        except Exception as e1:
            self.LogErrorLine("Error reading " + configfilepath + "genmqtt.conf: " + str(e1))
            self.console.error("Error reading " + configfilepath + "genmqtt.conf: " + str(e1))
            sys.exit(1)

        try:
            self.MQTTclient = mqtt.Client(client_id = "genmon")
            if self.Username != None and len(self.Username) and self.Password != None:
                self.MQTTclient.username_pw_set(self.Username, password=self.Password)

            self.MQTTclient.on_connect = self.on_connect
            self.MQTTclient.on_message = self.on_message


            if len(self.CertificateAuthorityPath):
                if os.path.isfile(self.CertificateAuthorityPath):
                    cert_reqs = ssl.CERT_REQUIRED
                    if self.CertReqs.lower() == "required":
                        cert_reqs = ssl.CERT_REQUIRED
                    elif self.CertReqs.lower() == "optional":
                        cert_reqs = ssl.CERT_REQUIRED
                    elif self.CertReqs.lower() == "none":
                        cert_reqs = ssl.CERT_NONE
                    else:
                        self.LogError("Error: invalid cert required specified, defaulting to required: " + self.self.CertReq)

                    use_tls = ssl.PROTOCOL_TLSv1
                    if self.TLSVersion == "1.0" or self.TLSVersion == "1":
                        use_tls = ssl.PROTOCOL_TLSv1
                    elif self.TLSVersion == "1.1":
                        use_tls = ssl.PROTOCOL_TLSv1_1
                    elif self.TLSVersion == "1.2":
                        use_tls = ssl.PROTOCOL_TLSv1_2
                    else:
                        self.LogError("Error: invalid TLS version specified, defaulting to 1.0: " + self.TLSVersion)
                    self.MQTTclient.tls_set(ca_certs = self.CertificateAuthorityPath,cert_reqs = cert_reqs, tls_version = use_tls )
                    self.MQTTPort = 8883    # port for SSL
                else:
                    self.LogError("Error: Unable to  find CA cert file: " + self.CertificateAuthorityPath)

            self.MQTTclient.connect(self.MQTTAddress, self.MQTTPort, 60)

            self.Push = MyGenPush(host = self.MonitorAddress,
                log = self.log, callback = self.PublishCallback,
                polltime = self.PollTime , blacklist = self.BlackList,
                flush_interval = self.FlushInterval, use_numeric = self.UseNumeric,
                debug = self.Debug, port = port, loglocation = loglocation)

            atexit.register(self.Close)
            signal.signal(signal.SIGTERM, self.Close)
            signal.signal(signal.SIGINT, self.Close)

            self.MQTTclient.loop_start()
        except Exception as e1:
            self.LogErrorLine("Error in MyMQTT init: " + str(e1))
            self.console.error("Error in MyMQTT init: " + str(e1))
            sys.exit(1)
Ejemplo n.º 22
0
class GenTankData(MySupport):

    #------------ GenTankData::init---------------------------------------------
    def __init__(self,
                 log=None,
                 loglocation=ProgramDefaults.LogPath,
                 ConfigFilePath=MyCommon.DefaultConfPath,
                 host=ProgramDefaults.LocalHost,
                 port=ProgramDefaults.ServerPort,
                 console=None):

        super(GenTankData, self).__init__()

        self.LogFileName = os.path.join(loglocation, "gentankdiy.log")
        self.AccessLock = threading.Lock()

        self.log = log
        self.console = console
        self.MonitorAddress = host

        configfile = os.path.join(ConfigFilePath, 'gentankdiy.conf')
        try:
            if not os.path.isfile(configfile):
                self.LogConsole("Missing config file : " + configfile)
                self.LogError("Missing config file : " + configfile)
                sys.exit(1)

            self.config = MyConfig(filename=configfile,
                                   section='gentankdiy',
                                   log=self.log)

            self.gauge_type = self.config.ReadValue('gauge_type',
                                                    return_type=int,
                                                    default=1)

            if self.MonitorAddress == None or not len(self.MonitorAddress):
                self.MonitorAddress = ProgramDefaults.LocalHost

        except Exception as e1:
            self.LogErrorLine("Error reading " + configfile + ": " + str(e1))
            self.LogConsole("Error reading " + configfile + ": " + str(e1))
            sys.exit(1)

        try:
            if self.gauge_type == 1:
                self.gauge = GaugeDIY1(self.config,
                                       log=self.log,
                                       console=self.console)
            elif self.gauge_type == 2:
                self.gauge = GaugeDIY2(self.config,
                                       log=self.log,
                                       console=self.console)
            else:
                self.LogError("Invalid guage type: " + str(self.gauge_type))
                sys.exit(1)

            self.debug = self.gauge.debug
            self.Generator = ClientInterface(host=self.MonitorAddress,
                                             port=port,
                                             log=self.log)

            # start thread monitor time for exercise
            self.Threads["TankCheckThread"] = MyThread(self.TankCheckThread,
                                                       Name="TankCheckThread",
                                                       start=False)

            if not self.gauge.InitADC():
                self.LogError("InitADC failed, exiting")
                sys.exit(1)

            self.Threads["TankCheckThread"].Start()

            signal.signal(signal.SIGTERM, self.SignalClose)
            signal.signal(signal.SIGINT, self.SignalClose)

        except Exception as e1:
            self.LogErrorLine("Error in GenTankData init: " + str(e1))
            self.console.error("Error in GenTankData init: " + str(e1))
            sys.exit(1)

    #----------  GenTankData::SendCommand --------------------------------------
    def SendCommand(self, Command):

        if len(Command) == 0:
            return "Invalid Command"

        try:
            with self.AccessLock:
                data = self.Generator.ProcessMonitorCommand(Command)
        except Exception as e1:
            self.LogErrorLine("Error calling  ProcessMonitorCommand: " +
                              str(Command))
            data = ""

        return data

    # ---------- GenTankData::TankCheckThread-----------------------------------
    def TankCheckThread(self):

        time.sleep(1)

        while True:
            try:

                dataforgenmon = {}

                tankdata = self.gauge.GetGaugeData()
                if tankdata != None:
                    dataforgenmon["Tank Name"] = "External Tank"
                    dataforgenmon["Capacity"] = 0
                    dataforgenmon["Percentage"] = tankdata

                    retVal = self.SendCommand("generator: set_tank_data=" +
                                              json.dumps(dataforgenmon))
                    self.LogDebug(retVal)
                if self.WaitForExit("TankCheckThread",
                                    float(self.gauge.PollTime * 60)):
                    return
            except Exception as e1:
                self.LogErrorLine("Error in TankCheckThread: " + str(e1))
                if self.WaitForExit("TankCheckThread",
                                    float(self.gauge.PollTime * 60)):
                    return

    # ----------GenTankData::SignalClose----------------------------------------
    def SignalClose(self, signum, frame):

        self.Close()
        sys.exit(1)

    # ----------GenTankData::Close----------------------------------------------
    def Close(self):

        self.KillThread("TankCheckThread")
        self.gauge.Close()
        self.Generator.Close()
Ejemplo n.º 23
0
class Loader(MySupport):

    def __init__(self,
        start = False,
        stop = False,
        hardstop = False,
        loglocation = ProgramDefaults.LogPath,
        log = None,
        localinit = False,
        ConfigFilePath = ProgramDefaults.ConfPath):

        self.Start = start
        self.Stop = stop
        self.HardStop = hardstop


        self.ConfigFilePath = ConfigFilePath

        self.ConfigFileName = "genloader.conf"
        # log errors in this module to a file
        if localinit == True:
            self.configfile = self.ConfigFileName
        else:
            self.configfile = self.ConfigFilePath + self.ConfigFileName

        self.ModulePath = os.path.dirname(os.path.realpath(__file__)) + "/"
        self.ConfPath = os.path.dirname(os.path.realpath(__file__)) + "/conf/"


        # log errors in this module to a file
        if log == None:
            self.log = SetupLogger("genloader", loglocation + "genloader.log")
        else:
            self.log = log

        self.console = SetupLogger("genloader_console", log_file = "", stream = True)

        try:
            if self.Start:
                if not self.CheckSystem():
                    self.LogInfo("Error check system readiness. Exiting")
                    sys.exit(2)

            self.CachedConfig = {}

            if not os.path.isdir(self.ConfigFilePath):
                try:
                    os.mkdir(self.ConfigFilePath)
                except Exception as e1:
                    self.LogInfo("Error creating target config directory: " + str(e1), LogLine = True)

            # check to see if genloader.conf is present, if not copy it from genmon directory
            if not os.path.isfile(self.configfile):
                self.LogInfo("Warning: unable to find config file: " + self.configfile + " Copying file to " + self.ConfigFilePath +  " directory.")
                if os.path.isfile(self.ConfPath + self.ConfigFileName):
                    copyfile(self.ConfPath + self.ConfigFileName , self.configfile)
                else:
                    self.LogInfo("Unable to find config file.")
                    sys.exit(2)

            self.config = MyConfig(filename = self.configfile, section = "genmon", log = self.log)
            if not self.GetConfig():
                self.LogInfo("Error reading config file. Exiting")
                sys.exit(2)

            if not self.ValidateConfig():
                self.LogInfo("Error validating config. Exiting")
                sys.exit(2)

            self.LoadOrder = self.GetLoadOrder()

            if self.Stop:
                self.StopModules()
                time.sleep(2)

            if self.Start:
                self.StartModules()
        except Exception as e1:
            self.LogErrorLine("Error in init: " + str(e1))

    #---------------------------------------------------------------------------
    def CheckSystem(self):

        # this function checks the system to see if the required libraries are
        # installed. If they are not then an attempt is made to install them.
        ModuleList = [
            # [import name , install name]
            ['flask','flask'],
            ['configparser','configparser'],
            ['serial','pyserial'],
            ['crcmod','crcmod'],
            ['pyowm','pyowm'],
            ['pytz','pytz'],
            ['pysnmp','pysnmp']
        ]
        try:
            ErrorOccured = False
            for Module in ModuleList:
                if not self.LibraryIsInstalled(Module[0]):
                    self.LogInfo("Warning: required library " + Module[1] + " not installed. Attempting to install....")
                    if not self.InstallLibrary(Module[1]):
                        self.LogInfo("Error: unable to install library " + Module[1])
                        ErrorOccured = True
            return not ErrorOccured
        except Exception as e1:
            self.LogInfo("Error in CheckSystem: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    @staticmethod
    def OneTimeMaint(ConfigFilePath, log):

        FileList = {
              "feedback.json" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "outage.txt" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "kwlog.txt" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "maintlog.json" : os.path.dirname(os.path.realpath(__file__)) + "/",
              "Feedback_dat" : os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
              "Message_dat" : os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/",
              'genmon.conf' : "/etc/",
              'genserv.conf': "/etc/",
              'gengpio.conf' : "/etc/",
              'gengpioin.conf': "/etc/",
              'genlog.conf' : "/etc/",
              'gensms.conf' : "/etc/",
              'gensms_modem.conf': "/etc/",
              'genpushover.conf': "/etc/",
              'gensyslog.conf' : "/etc/",
              'genmqtt.conf' : "/etc/",
              'genslack.conf': "/etc/",
              'genexercise.conf' : "/etc/",
              'genemail2sms.conf' :  "/etc/",
              'genloader.conf' :  "/etc/",
              'mymail.conf' : "/etc/",
              'mymodem.conf' : "/etc/"
        }
        try:
            # Check to see if we have done this already by checking files in the genmon source directory
            if (not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/genmonlib/Message_dat") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/maintlog.json") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/outage.txt") and
            not os.path.isfile(os.path.dirname(os.path.realpath(__file__)) + "/kwlog.txt") and
            not os.path.isfile("/etc/genmon.conf")):
                return False
            # validate target directory
            if not os.path.isdir(ConfigFilePath):
                try:
                    os.mkdir(ConfigFilePath)
                    if not os.access(ConfigFilePath + File, os.R_OK):
                        pass
                except Exception as e1:
                    log.error("Error validating target directory: " + str(e1), LogLine = True)

            # move files
            for File, Path in FileList.items():
                try:
                    SourceFile = Path + File
                    if os.path.isfile(SourceFile):
                        log.error("Moving " + SourceFile + " to " + ConfigFilePath )
                        if not MySupport.CopyFile(SourceFile, ConfigFilePath + File, move = True, log = log):
                            log.error("Error: using alternate move method")
                            move(SourceFile , ConfigFilePath + File)
                        if not os.access(ConfigFilePath + File, os.R_OK):
                            pass
                except Exception as e1:
                    log.error("Error moving " + SourceFile)
        except Exception as e1:
            log.error("Error moving files: " + str(e1), LogLine = True)
        return True

    #---------------------------------------------------------------------------
    def LibraryIsInstalled(self, libraryname):

        try:
            import importlib
            my_module = importlib.import_module(libraryname)
            return True
        except Exception as e1:
            return False

    #---------------------------------------------------------------------------
    def InstallLibrary(self, libraryname):

        try:
            process = Popen(['pip','install', libraryname], stdout=PIPE, stderr=PIPE)
            output, _error = process.communicate()

            if _error:
                self.LogInfo("Error in InstallLibrary using pip : " + libraryname + " : " + str(_error))
            rc = process.returncode
            return True

        except Exception as e1:
            self.LogInfo("Error installing module: " + libraryname + ": "+ str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def ValidateConfig(self):

        ErrorOccured = False
        if not len(self.CachedConfig):
            self.LogInfo("Error: Empty configruation found.")
            return False

        for Module, Settiings in self.CachedConfig.items():
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not os.path.isfile(self.ModulePath + self.CachedConfig[Module]["module"]):
                        self.LogInfo("Enable to find file " + self.ModulePath + self.CachedConfig[Module]["module"])
                        ErrorOccured = True

                # validate config file and if it is not there then copy it.
                if not self.CachedConfig[Module]["conffile"] == None and len(self.CachedConfig[Module]["conffile"]):
                    ConfFileList = self.CachedConfig[Module]["conffile"].split(",")
                    for ConfigFile in ConfFileList:
                        ConfigFile = ConfigFile.strip()
                        if not os.path.isfile(self.ConfigFilePath + ConfigFile):
                            if os.path.isfile(self.ConfPath + ConfigFile):
                                self.LogInfo("Copying " + ConfigFile + " to " + self.ConfigFilePath )
                                copyfile(self.ConfPath + ConfigFile , self.ConfigFilePath + ConfigFile)
                            else:
                                self.LogInfo("Enable to find config file " + self.ConfPath + ConfigFile)
                                ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error validating config for " + Module + " : " + str(e1), LogLine = True)
                return False

        return not ErrorOccured

    #---------------------------------------------------------------------------
    def AddEntry(self, section = None, module = None, conffile = "", args = "", priority = '2'):

        try:
            if section == None or module == None:
                return
            self.config.WriteSection(section)
            self.config.WriteValue('module', module, section = section)
            self.config.WriteValue('enable', 'False', section = section)
            self.config.WriteValue('hardstop', 'False', section = section)
            self.config.WriteValue('conffile', conffile, section = section)
            self.config.WriteValue('args', args, section = section)
            self.config.WriteValue('priority', priority, section = section)
        except Exception as e1:
            self.LogInfo("Error in AddEntry: " + str(e1), LogLine = True)
        return

    #---------------------------------------------------------------------------
    def UpdateIfNeeded(self):

        try:
            self.config.SetSection("gengpioin")
            if not self.config.HasOption('conffile'):
                self.config.WriteValue('conffile', "gengpioin.conf", section = "gengpioin")
                self.LogError("Updated entry gengpioin.conf")
            else:
                defValue = self.config.ReadValue('conffile', default = "")
                if not len(defValue):
                    self.config.WriteValue('conffile', "gengpioin.conf", section = "gengpioin")
                    self.LogError("Updated entry gengpioin.conf")

        except Exception as e1:
            self.LogInfo("Error in UpdateIfNeeded: " + str(e1), LogLine = True)

    #---------------------------------------------------------------------------
    def GetConfig(self):

        try:

            Sections = self.config.GetSections()
            ValidSections = ['genmon', 'genserv', 'gengpio', 'gengpioin', 'genlog', 'gensms', 'gensms_modem', 'genpushover', 'gensyslog', 'genmqtt', 'genslack', 'genexercise', 'genemail2sms', 'gentankutil', 'genalexa', 'gensnmp']
            for entry in ValidSections:
                if not entry in Sections:
                    if entry == 'genslack':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genslack.py', conffile = 'genslack.conf')
                    if entry == 'genexercise':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genexercise.py', conffile = 'genexercise.conf')
                    if entry == 'genemail2sms':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genemail2sms.py', conffile = 'genemail2sms.conf')
                    if entry == 'gentankutil':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'gentankutil.py', conffile = 'gentankutil.conf')
                    if entry == 'genalexa':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'genalexa.py', conffile = 'genalexa.conf')
                    if entry == 'gensnmp':
                        self.LogError("Warning: Missing entry: " + entry + " , adding entry")
                        self.AddEntry(section = entry, module = 'gensnmp.py', conffile = 'gensnmp.conf')
                    else:
                        self.LogError("Warning: Missing entry: " + entry)

            self.UpdateIfNeeded()

            Sections = self.config.GetSections()
            for SectionName in Sections:
                TempDict = {}
                self.config.SetSection(SectionName)
                if self.config.HasOption('module'):
                    TempDict['module'] = self.config.ReadValue('module')
                else:
                    TempDict['module'] = None

                if self.config.HasOption('enable'):
                    TempDict['enable'] = self.config.ReadValue('enable', return_type = bool)
                else:
                    TempDict['enable'] = False

                if self.config.HasOption('hardstop'):
                    TempDict['hardstop'] = self.config.ReadValue('hardstop', return_type = bool)
                else:
                    TempDict['hardstop'] = False

                if self.config.HasOption('conffile'):
                    TempDict['conffile'] = self.config.ReadValue('conffile')
                else:
                    TempDict['conffile'] = None

                if self.config.HasOption('args'):
                    TempDict['args'] = self.config.ReadValue('args')
                else:
                    TempDict['args'] = None

                if self.config.HasOption('priority'):
                    TempDict['priority'] = self.config.ReadValue('priority', return_type = int, default = None)
                else:
                    TempDict['priority'] = None

                if self.config.HasOption('postloaddelay'):
                    TempDict['postloaddelay'] = self.config.ReadValue('postloaddelay', return_type = int, default = 0)
                else:
                    TempDict['postloaddelay'] = 0

                if self.config.HasOption('pid'):
                    TempDict['pid'] = self.config.ReadValue('pid', return_type = int, default = 0, NoLog = True)
                else:
                    TempDict['pid'] = 0

                self.CachedConfig[SectionName] = TempDict
            return True

        except Exception as e1:
            self.LogInfo("Error parsing config file: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    def ConvertToInt(self, value, default = None):

        try:
            return int(str(value))
        except:
            return default

    #---------------------------------------------------------------------------
    def GetLoadOrder(self):

        LoadOrder = []
        LoadDict = {}
        try:
            for Module, Settiings in self.CachedConfig.items():
                # get the load order of all modules, even if they are disabled
                # since we need to stop all modules (even disabled ones) if the
                # conf file changed
                try:
                    if self.CachedConfig[Module]["priority"] == None:
                        LoadDict[Module] = 99
                    elif self.CachedConfig[Module]["priority"] >= 0:
                        LoadDict[Module] = self.CachedConfig[Module]["priority"]
                    else:
                        LoadDict[Module] = 99
                except Exception as e1:
                    self.LogInfo("Error reading load order (retrying): " + str(e1), LogLine = True)
            #lambda kv: (-kv[1], kv[0])
            for key, value in sorted(LoadDict.items(), key=lambda kv: (-kv[1], kv[0])):
            #for key, value in sorted(LoadDict.iteritems(), key=lambda (k,v): (v,k)):
                LoadOrder.append(key)
        except Exception as e1:
            self.LogInfo("Error reading load order: " + str(e1), LogLine = True)

        return LoadOrder
    #---------------------------------------------------------------------------
    def StopModules(self):

        self.LogConsole("Stopping....")
        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to stop.")
            return False
        ErrorOccured = False
        for Module in self.LoadOrder:
            try:
                if not self.UnloadModule(self.ModulePath, self.CachedConfig[Module]["module"], pid = self.CachedConfig[Module]["pid"],HardStop = self.CachedConfig[Module]["hardstop"], UsePID = True):
                    self.LogInfo("Error stopping " + Module)
                    ErrorOccured = True
            except Exception as e1:
                self.LogInfo("Error stopping module " + Module + " : " + str(e1), LogLine = True)
                return False
        return not ErrorOccured
    #---------------------------------------------------------------------------
    def StartModules(self):

        self.LogConsole("Starting....")

        if not len(self.LoadOrder):
            self.LogInfo("Error, nothing to start.")
            return False
        ErrorOccured = False
        for Module in reversed(self.LoadOrder):
            try:
                if self.CachedConfig[Module]["enable"]:
                    if not self.LoadModule(self.ModulePath, self.CachedConfig[Module]["module"], args = self.CachedConfig[Module]["args"]):
                        self.LogInfo("Error starting " + Module)
                        ErrorOccured = True
                    if not self.CachedConfig[Module]["postloaddelay"] == None and self.CachedConfig[Module]["postloaddelay"] > 0:
                        time.sleep(self.CachedConfig[Module]["postloaddelay"])
            except Exception as e1:
                self.LogInfo("Error starting module " + Module + " : " + str(e1), LogLine = True)
                return False
        return not ErrorOccured
    #---------------------------------------------------------------------------
    def LoadModuleAlt(self, modulename, args = None):
        try:
            self.LogConsole("Starting " + modulename)
            # to load as a background process we just use os.system since Popen
            # is problematic in doing this
            CommandString = sys.executable + " " + modulename
            if args != None and len(args):
                CommandString += " " + args
            CommandString += " &"
            os.system(CommandString)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine = True)
            return False

    #---------------------------------------------------------------------------
    def LoadModule(self, path, modulename, args = None):
        try:
            fullmodulename = path + modulename
            if args != None:
                self.LogConsole("Starting " + fullmodulename + " " + args)
            else:
                self.LogConsole("Starting " + fullmodulename)
            try:
                from subprocess import DEVNULL # py3k
            except ImportError:
                import os
                DEVNULL = open(os.devnull, 'wb')

            if not len(args):
                args = None

            if "genserv.py" in modulename:
                OutputStream = DEVNULL
            else:
                OutputStream = subprocess.PIPE

            executelist = [sys.executable, fullmodulename]
            if args != None:
                executelist.extend(args.split(" "))
            # This will make all the programs use the same config files
            executelist.extend(["-c", self.ConfigFilePath])
            # close_fds=True
            pid = subprocess.Popen(executelist, stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
            self.UpdatePID(modulename, pid.pid)
            return True

        except Exception as e1:
            self.LogInfo("Error loading module " + modulename + ": " + str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def UnloadModule(self, path, modulename, pid = None, HardStop = False, UsePID = False):
        try:
            LoadInfo = []
            if UsePID:
                if pid == None or pid == "" or pid == 0:
                    return True
                LoadInfo.append("kill")
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append(str(pid))
            else:
                LoadInfo.append('pkill')
                if HardStop or self.HardStop:
                    LoadInfo.append('-9')
                LoadInfo.append('-u')
                LoadInfo.append('root')
                LoadInfo.append('-f')
                LoadInfo.append(modulename)

            self.LogConsole("Stopping " + modulename)
            process = Popen(LoadInfo, stdout=PIPE)
            output, _error = process.communicate()
            rc = process.returncode
            self.UpdatePID(modulename, "")
            return True

        except Exception as e1:
            self.LogInfo("Error loading module: " + str(e1), LogLine = True)
            return False
    #---------------------------------------------------------------------------
    def UpdatePID(self, modulename, pid = None):

        try:
            filename = os.path.splitext(modulename)[0]    # remove extension
            self.config.SetSection(filename)
            self.config.WriteValue("pid", str(pid))
        except Exception as e1:
            self.LogInfo("Error writing PID for " + modulename + " : " + str(e1))
Ejemplo n.º 24
0
    if not os.path.isfile(os.path.join(ConfigFilePath, 'mymail.conf')):
        console.error("Missing config file : " +
                      os.path.join(ConfigFilePath, 'mymail.conf'))
        log.error("Missing config file : " +
                  os.path.join(ConfigFilePath, 'mymail.conf'))
        sys.exit(1)

    try:

        SiteName = GetSiteName()
        config = MyConfig(filename=os.path.join(ConfigFilePath,
                                                'genemail2sms.conf'),
                          section='genemail2sms',
                          log=log)

        DestinationEmail = config.ReadValue('destination', default="")

        if DestinationEmail == "" or (not "@" in DestinationEmail):
            log.error("Missing parameter in " +
                      os.path.join(ConfigFilePath, 'genemail2sms.conf'))
            console.error("Missing parameter in " +
                          os.path.join(ConfigFilePath, 'genemail2sms.conf'))
            sys.exit(1)

        # init mail, start processing incoming email
        MyMail = MyMail(loglocation=loglocation,
                        log=log,
                        ConfigFilePath=ConfigFilePath)
    except Exception as e1:
        log.error("Error reading " +
                  os.path.join(ConfigFilePath, 'genemail2sms.conf') + ": " +
Ejemplo n.º 25
0
        # Set the signal handler
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)

        Threads = {}
        UseCallbacks = False
        DefaultTrigger = GPIO.FALLING
        DefaultPullup = GPIO.PUD_UP
        DefaultBounce = 0

        if os.path.isfile(os.path.join(ConfigFilePath, 'gengpioin.conf')):
            config = MyConfig(filename=os.path.join(ConfigFilePath,
                                                    'gengpioin.conf'),
                              section='gengpioin',
                              log=log)
            Trigger = config.ReadValue('trigger', default="falling")
            if Trigger.lower() == "rising":
                DefaultTrigger = GPIO.RISING
            elif Trigger.lower() == "both":
                DefaultTrigger = GPIO.BOTH
            else:
                DefaultTrigger = GPIO.FALLING

            ResistorPull = config.ReadValue('resistorpull', default="up")
            if ResistorPull.lower() == "down":
                DefaultPullup = GPIO.PUD_DOWN
            elif ResistorPull.lower() == "off":
                DefaultPullup = GPIO.PUD_OFF
            else:
                DefaultPullup = GPIO.PUD_UP