#!/usr/bin/python3    
#-*- coding=utf-8 -*-
from __future__ import print_function
import sys
from time import *
import socket
import json
import os
import operator
import struct
import logging
import logging.config
from pprint import *
import numpy as np
from datetime import datetime, timedelta
from pysnmp.hlapi import *
#from time import strftime, localtime
from threading import Timer
import sched

appPath="./upsMonitor.d"
viewMode=1
#viewMode查看模式不会记录
config = {}
snmp = {}
defConfigValue=("Modbus","127.0.0.1",300,60,180,"on","shutdown -h now")
defsnmpValue=("2","eastups","admin","12345678","12345678")
keyNames = ("Agreement","Ip Address","ShutDown Delay for Ac Power Failed(s)",
                  "ShutDown Delay for Battery Low(s)",
                  "UPS Turn Off Delay Time(s)",                  
                  "Turn off UPS after System Shutdown",
                  "ShutDown cmd"
)
keyNames_2=("snmp edition","community","username","userpassword","privacy protection password"
)
keys=("Agreement","IpAddress","ShutDownDelayForAcFail","ShutDownDelayForBatteryLow","UPSTurnOffDelay","TurnOffUPS","shutDownCmd")
keys_2=("snmp edition","community","username","userpassword","privacy protection password")
upsWellKnownAlams={
    '1.3.6.1.2.1.33.1.6.3.1':'upsAlarmBatteryBad',
    '1.3.6.1.2.1.33.1.6.3.2':'upsAlarmOnBattery',
    '1.3.6.1.2.1.33.1.6.3.3':'upsAlarmLowBattery',
    '1.3.6.1.2.1.33.1.6.3.4':'upsAlarmDepletedBattery',
    '1.3.6.1.2.1.33.1.6.3.5':'upsAlarmTemBad',
    '1.3.6.1.2.1.33.1.6.3.6':'upsAlarmInputBad',
    '1.3.6.1.2.1.33.1.6.3.7':'upsAlarmOutputBad',
    '1.3.6.1.2.1.33.1.6.3.8':'upsAlarmOutputOverload',
    '1.3.6.1.2.1.33.1.6.3.9':'upsAlarmOnBypass',
    '1.3.6.1.2.1.33.1.6.3.10':'upsAlarmBypassBad',
    '1.3.6.1.2.1.33.1.6.3.11':'upsAlarmOutputOffAsRequested',
    '1.3.6.1.2.1.33.1.6.3.12':'upsAlarmUpsOffAsRequested',
    '1.3.6.1.2.1.33.1.6.3.13':'upsAlarmChargerFailed',
    '1.3.6.1.2.1.33.1.6.3.14':'upsAlarmUpsOutputOff',
    '1.3.6.1.2.1.33.1.6.3.15':'upsAlarmUpsSystemOff',
    '1.3.6.1.2.1.33.1.6.3.16':'upsAlarmFanFailure',
    '1.3.6.1.2.1.33.1.6.3.17':'upsAlarmFuseFailure',
    '1.3.6.1.2.1.33.1.6.3.18':'upsAlarmGeneralFault',
    '1.3.6.1.2.1.33.1.6.3.19':'upsAlarmDiagnosticTestFailed',
    '1.3.6.1.2.1.33.1.6.3.20':'upsAlarmCommunicationsLost',
    '1.3.6.1.2.1.33.1.6.3.21':'upsAlarmAwaitingPower',
    '1.3.6.1.2.1.33.1.6.3.22':'upsAlarmShutdownPending',
    '1.3.6.1.2.1.33.1.6.3.23':'upsAlarmShutdownImminent',
    '1.3.6.1.2.1.33.1.6.3.24':'upsAlarmTestInProgress'
 }

modbusPort = 502
index = 0
def snmpv2_upsshutdown():
    from pysnmp.entity.rfc3413.oneliner import cmdgen
    from pysnmp.proto import rfc1902
    t=int(getSettings("UPS Turn Off Delay Time(s)"))
    with open(appPath+"/snmp.json","r")as a:
     json_str=a.read()
     agree=json.loads(json_str)
     cmdGen = cmdgen.CommandGenerator()
     errorIndication, errorStatus, errorindex, varBinds = cmdGen.setCmd(
     cmdgen.CommunityData(agree["community"], agree["community"], 1),
     cmdgen.UdpTransportTarget((getSettings("Ip Address"),161)),
     ('.1.3.6.1.2.1.33.1.8.2.0',rfc1902.Integer(t))
     )

    if errorIndication:
        print(errorIndication)
    elif errorStatus:
        print('%s at %s' % (
                errorStatus.prettyPrint(),
                errorindex and varBinds[int(errorindex)-1][0] or '?'
            )
        )      

def snmpv3_set(ip,user,hash_key,cry_key,oid):
    from pysnmp.proto import rfc1902
    t=int(getSettings("UPS Turn Off Delay Time(s)"))
    iterator = setCmd(
        SnmpEngine(),
        UsmUserData(user,hash_key,cry_key,#第一个为snmp用户名，第二个为认证密码，第三个为加密密码
                    authProtocol=usmHMACSHAAuthProtocol,#认证方式
                    privProtocol=usmDESPrivProtocol),#认证密码
        UdpTransportTarget((ip, 161)),
        ContextData(),
        ObjectType(ObjectIdentity(oid),rfc1902.Integer(t))
        #ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))
    )

    errorIndication, errorStatus, errorIndex, varBinds = next(iterator)

    if errorIndication:
        print(errorIndication)

    elif errorStatus:
        print('%s at %s' % (errorStatus.prettyPrint(),
                            errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))

def snmpshutDownSystem():
    on=getSettings("Turn off UPS after System Shutdown")
    if on == "on":
        #setUpsShutDown(getSettings("Ip Address"),modbusPort)
     with open(appPath+"/snmp.json","r")as a:
      json_str=a.read()
      agree=json.loads(json_str)
      if agree["snmp edition"]=="2":
        snmpv2_upsshutdown()
      if agree["snmp edition"]=="3":
      #snmpv3_get_all_info(ip,agree["username"],agree["userpassword"],agree["privacy protection password"],oid)
        snmpv3_set(getSettings("Ip Address"),agree["username"],agree["userpassword"],agree["privacy protection password"],'.1.3.6.1.2.1.33.1.8.2.0')
    os.system("sync")
    os.system("sync")
    sleep(2)
    cmd=getSettings("ShutDown cmd")
    print(cmd)
    os.system(cmd) 

def shutDownSystem():
    on=getSettings("Turn off UPS after System Shutdown")
    if on == "on":
        setUpsShutDown(getSettings("Ip Address"),modbusPort)

    os.system("sync")
    os.system("sync")
    sleep(2)
    cmd=getSettings("ShutDown cmd")
    print(cmd)
    os.system(cmd)

def getTimeStr(t=localtime()):
    return strftime("%Y-%m-%d %X", t)

InputAcCount = 0
preTime = time()
batteryLowTime = time()
isHasPreTime = 0
PreStatusAlarm = 0
isHasBatteryLowTime = 0
Snmp_Comm_Timeout = 0
upsAlarmCommunicationLostCount = 0
upsAlarmCommunicationLost = 0
currentStateLabel = "Status: Normal"  # 系统当前状态显示

def StateLog(info):
    log_name = appPath+"/ups.log"
    logger = logging.getLogger("upsMonitor")
    logger.setLevel(logging.DEBUG)
    handle = logging.handlers.RotatingFileHandler(
    log_name, maxBytes=512*1024, backupCount=1)
    logger.addHandler(handle)
    logger.debug(info)
    logger.removeHandler(handle)

def ErrorLog(info):
    errlog_name=appPath+"/error.log"
    errlogger = logging.getLogger("upsError")
    errlogger.setLevel(logging.ERROR)
    errhandle = logging.handlers.RotatingFileHandler(
    errlog_name, maxBytes=512*1024, backupCount=1)
    errlogger.addHandler(errhandle)
    errlogger.error(info)
    errlogger.removeHandler(errhandle)
    
def SnmpLog(info):
    log_name = appPath+"/snmpdate.log"
    logger = logging.getLogger("snmpdata")
    logger.setLevel(logging.CRITICAL)
    handle = logging.handlers.RotatingFileHandler(
    log_name, maxBytes=512*1024, backupCount=1)
    logger.addHandler(handle)
    logger.critical(info)
    logger.removeHandler(handle)

def JudgetThread(inPutAcStatus, batteryStatus,viewMode):
    ACfail_Flag = 0
    RecordBatteryStatus = 0
    global InputAcCount
    global preTime
    global batteryLowTime
    global isHasPreTime
    global PreStatusAlarm
    global isHasBatteryLowTime
    global Snmp_Comm_Timeout
    global currentStateLabel
    # 市电故障判断   

    if inPutAcStatus == 1:
        InputAcCount+=1
        if InputAcCount>=3:
            ACfail_Flag = 1
    else:
        ACfail_Flag = 0
        InputAcCount=0

    if ACfail_Flag:
        if not isHasPreTime:
            preTime = time()
            isHasPreTime = 1
            CurrentStatusAlarm = 0
            if CurrentStatusAlarm != PreStatusAlarm:
                PreStatusAlarm = CurrentStatusAlarm
                if not viewMode:
                    StateLog("%s--%s\r\n" % (getTimeStr(), "ACfail"))
    else:
        isHasPreTime = 0
        currentStateLabel = "Status: Normal"
        if PreStatusAlarm == 0:
            PreStatusAlarm = CurrentStatusAlarm = -1
            if not viewMode:
                StateLog("%s--%s\r\n" % (getTimeStr(), "AC Normal"))

    if(isHasPreTime):
        ACShutdownTime = int(getSettings(
            "ShutDown Delay for Ac Power Failed(s)"))
        curTime = time()

        LastTime = ACShutdownTime - curTime + preTime
        if LastTime <= 0:
            LastTime = 0
            if not viewMode:
                shutDownSystem()
                StateLog("%s--%s\r\n" % (getTimeStr(), "ShutDown by Ac Power Failed"))

        if(ACfail_Flag):
                currentStateLabel="Status: %s  %.1f Min" %("ACFailShutDown  ", LastTime/60)
        else:
                currentStateLabel="%s" % "Status: Normal"

    RecordBatteryStatus = batteryStatus
    
    if RecordBatteryStatus == 3:  # 电池电压低
        if not isHasBatteryLowTime:
            batteryLowTime = time()
            isHasBatteryLowTime = 1
            CurrentStatusAlarm = 1
            if CurrentStatusAlarm != PreStatusAlarm:
                PreStatusAlarm = CurrentStatusAlarm
                if not viewMode:
                    StateLog("%s--%s\r\n" % (getTimeStr(), "BatteryLow"))
    else:
        isHasBatteryLowTime = 0

    if RecordBatteryStatus == 2:  # 电池正常
        if ACfail_Flag:
            currentStateLabel = "Status: %s  %.1f Min" % (
                "ACFailShutDown  ", LastTime/60)
        else:
            currentStateLabel = "Status: %s " % "Normal "

        CurrentStatusAlarm = 2
        if not CurrentStatusAlarm == PreStatusAlarm and (PreStatusAlarm == 1 or PreStatusAlarm == 3 or PreStatusAlarm == 4):
            PreStatusAlarm = CurrentStatusAlarm = -1
            if not viewMode:
                StateLog("%s--%s\r\n" % (getTimeStr(), "BatteryNormal"))

    elif RecordBatteryStatus == 1:  # 电池状态未知
        if(ACfail_Flag):
            currentStateLabel = "Status: %s  %.1f Min; BatteryUnknow!" % (
                "ACFailShutDown  ", LastTime/60)
        else:
            currentStateLabel = "Status: %s " % "BatteryUnknow "
        CurrentStatusAlarm = 3
        if  CurrentStatusAlarm != PreStatusAlarm:
            PreStatusAlarm = CurrentStatusAlarm
            if not viewMode:
                StateLog("%s--%s\r\n" % (getTimeStr(), "BatteryUnknow"))

    elif RecordBatteryStatus == 4:
        if(ACfail_Flag):
            currentStateLabel = "Status: %s  %.1f Min; BatteryDepleted" % (
                "ACFailShutDown", LastTime/60)
        else:
            currentStateLabel = "Status: BatteryDepleted"
        CurrentStatusAlarm = 4
        if  CurrentStatusAlarm != PreStatusAlarm:
            PreStatusAlarm = CurrentStatusAlarm
            if not viewMode:
                StateLog("%s--%s\r\n" % (getTimeStr(), "BatteryDepleted"))

    if isHasBatteryLowTime:
        BatteryLowSysShutDown = int(getSettings(
            "ShutDown Delay for Battery Low(s)"))
        curTime = time()
        BatLowLastTime = BatteryLowSysShutDown - curTime + batteryLowTime
        if BatLowLastTime <= 0:
            BatLowLastTime = 0
            if not viewMode:
                shutDownSystem()
                StateLog("%s--%s\r\n" % (getTimeStr(), "ShutDown by Battery Low"))

        if RecordBatteryStatus == 1:
            if ACfail_Flag:
                currentStateLabel = "Status: %s  %.1f Min; BatteryUnknow!" % (
                    "ACFailShutDown  ", LastTime/60)
            else:
                currentStateLabel = "Status: %s " % "BatteryUnknow "
        elif RecordBatteryStatus == 3:
            if ACfail_Flag:
                currentStateLabel = "Status: %s %.1f Min; BatteryLowShutDown  %1.f Min" % (
                    "ACFailShutDown", LastTime/60, BatLowLastTime/60)
            else:
                currentStateLabel = "Status: %s  %.1f Min" % (
                    "BatteryLowShutDown ", BatLowLastTime/60)

        elif RecordBatteryStatus == 4:
            if ACfail_Flag:
                currentStateLabel = "Status: %s  %.1f Min; BatteryDepleted" % (
                    "ACFailShutDown", LastTime/60)
            else:
                currentStateLabel = "Status: BatteryDepleted"


def getUpsShutDownTimeDelay(ipAddr, port):
    try:
        socket.setdefaulttimeout(1)
        s = socket.socket()
        s.connect((ipAddr, port))
        global index
        if index > 1000:
            index = 0
        else:
            index += 1
        data = struct.pack("3H6B", socket.htons(index), 0,
                           socket.htons(6), 0x01, 0x03, 0x00, 0x00, 0x00, 0x07)
        s.send(data)
        data = s.recv(12)
        print(repr(data))
    except Exception as e:
        ErrorLog("%s -- %s"%(getTimeStr(),str(e)))

def setUpsShutDown(ipAddr,port):
    try:
        
        socket.setdefaulttimeout(1)
        s = socket.socket()
        s.connect((ipAddr, port))
        global index
        if index > 1000:
            index = 0
        else:
            index += 1
        turnOffTime=int(getSettings("UPS Turn Off Delay Time(s)"))
        data = struct.pack("3H6B", socket.htons(index), 0,
                           socket.htons(6), 0x01, 0x06, 0x00, 0x07, turnOffTime>>8&0xff,turnOffTime&0xff)
        s.send(data)
        data = s.recv(12)
        
        s.close()
    except Exception as e:
        ErrorLog("%s -- %s"%(getTimeStr(),str(e)))

    
def getUpsAlarm(ipAddr, port):
    try:
        socket.setdefaulttimeout(1)
        s = socket.socket()
        s.connect((ipAddr, port))
        global index
        if index > 1000:
            index = 0
        else:
            index += 1
        data = struct.pack("3H6B", socket.htons(index), 0,
                           socket.htons(6), 0x01, 0x02, 0x01, 0x01, 0x00, 0x18)
        s.send(data)
        data = s.recv(12)
        _, alarm1,_,_ = struct.unpack("9s3B", data)
        if len(data)!=12:
            return []
        alarm=[]
        for i in range(0, 8):
            alarm.append((alarm1 >> i & 0x1))
        
        s.close()
        return alarm
    except Exception as e:
        ErrorLog("%s -- %s"%(getTimeStr(),str(e)))
    return []


def dataProcess(viewMode):
    #viewMode,查看模式不会记录也不会关机等操作
    i = 0
    global currentStateLabel
    global isHasBatteryLowTime
    global isHasPreTime
    global PreStatusAlarm
    upsAlarmCommunicationLostCount=0
    upsAlarmCommunicationLost=0
    snmpCommunicationCount=0
    printConfig(0)
    #get_all_info('192.168.163.196', 'eastups')
    ip = getSettings("Ip Address")
    #ro = getSettings_2("community") 
    with open(appPath+"/config.json","r")as f:
        json_str=f.read()
        edition=json.loads(json_str)
        if edition["Agreement"]=="snmp":
            #print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
            with open(appPath+"/snmp.json","r")as a:
             json_str=a.read()
             agree=json.loads(json_str)
             if agree["snmp edition"]=="2":            
               #get_all_info(ip,agree["community"])
               mymain_V2()
             if agree["snmp edition"]=="3":
               #"snmp edition","community","username","userpassword","privacy protection password"
               #snmpv3_get_all_info(ip,agree["username"],agree["userpassword"],agree["privacy protection password"],newtime)
               mymain_V3()
        if edition["Agreement"]=="Modbus":       
            while True:
                sleep(1)
                ip = getSettings("Ip Address")
                alarm = getUpsAlarm(ip, modbusPort)
              #  getUpsShutDownTimeDelay(ip, modbusPort)
                i += 1
                if len(alarm)==0:
                    currentStateLabel = "%s" % "Status: TimeOut(snmp)"
                    CurrentStatusAlarm = 5
                    snmpCommunicationCount+=1
                    if snmpCommunicationCount>=3:
                        if CurrentStatusAlarm != PreStatusAlarm:
                            PreStatusAlarm = CurrentStatusAlarm
                            if not viewMode:
                                StateLog("%s--%s\n\r" % (getTimeStr(), "TimeOut(snmp)"))

                        isHasBatteryLowTime = 0
                        isHasPreTime = 0
                else:
                    if PreStatusAlarm == 5:
                        PreStatusAlarm = CurrentStatusAlarm = -1
                        if not viewMode:
                            StateLog("%s--%s\n\r" % (getTimeStr(), "Status: Normal"))
                    snmpCommunicationCount=0
                    upsAlarmCommunicationLost=alarm[0]
                    inputAcState=alarm[6]
                    if alarm[3]==1:
                        batteryState=3#电池低电压
                    elif alarm[4] ==1:
                        batteryState=4#电池低容量
                    else:
                        batteryState=2#电池正常
                    if upsAlarmCommunicationLost !=1:
                        JudgetThread(inputAcState,batteryState,viewMode)
                
                if upsAlarmCommunicationLost:
                    currentStateLabel = "%s" % "Status: ups communication lost"
                    CurrentStatusAlarm = 6
                    upsAlarmCommunicationLostCount+=1
                    if upsAlarmCommunicationLostCount>=3:
                        if  CurrentStatusAlarm != PreStatusAlarm:
                            PreStatusAlarm = CurrentStatusAlarm
                            if not viewMode:
                                StateLog("%s--%s\r\n" %
                                        (getTimeStr(), "ups communication lost"))
                        isHasBatteryLowTime = 0
                        isHasPreTime = 0
                else:
                    if PreStatusAlarm == 6:
                        PreStatusAlarm = CurrentStatusAlarm = -1
                        if not viewMode:
                            StateLog("%s--%s\r\n" %
                                        (getTimeStr(), "ups communication connect"))
                    upsAlarmCommunicationLostCount=0
                if viewMode:    
                    sys.stdout.write("                                                            ")
                    sys.stdout.write("\r")
                    sys.stdout.write(currentStateLabel)
                    sys.stdout.write("\r")
                    sys.stdout.flush()
      
def printConfig(help):
    #keys = sorted(config.items(), key=operator.itemgetter(0))
    print("[General config]")
    for key in keyNames:
        i=keyNames.index(key)
        k=keys[i]
        print(str(i+1)+"."+key, ":", config[k])
    if(help==1):   
        print("")
        print("example:upsMonitor config 1=snmp")
        print("        upsMonitor config 2=127.0.0.1")
        print("        upsMonitor config 3=180")
        print("")
    with open(appPath+"/config.json","r")as f:
        json_str=f.read()
        edition=json.loads(json_str)
        if edition["Agreement"]=="snmp": 
           print("[Snmp Config]")       
           printsnmp()
           if(help==1):      
             printsnmphelp()

def printsnmp():
    #keys = sorted(config.items(), key=operator.itemgetter(0))
    with open(appPath+"/snmp.json","r")as f:
        json_str=f.read()
        edition=json.loads(json_str)
    if edition["snmp edition"]=="2":
     for key in keyNames_2[:-3]:
        i=keyNames_2.index(key)
        k=keys_2[i]
        print(str(i+1)+"."+key, ":", snmp[k])
    if edition["snmp edition"]=="3":
     for key in keyNames_2:
        i=keyNames_2.index(key)
        if i==1:
            continue
        elif i<1:    
            k=keys_2[i]
            print(str(i+1)+"."+key, ":", snmp[k])
        else:
            k=keys_2[i]
            print(str(i)+"."+key, ":", snmp[k])
    #print("")

def saveSettings(key, value):
    i=-1
    if key in keyNames:
        i=keys.index(key)
        key=keys[i]
    if key in ("1","2","3","4","5","6","7"):
        key=keys[int(key)-1]
    if value != config[key]:
            config[key] = value
            fd = open(appPath+"/config.json", "w")
            fd.write(json.dumps(config))
            os.fsync(fd)
            fd.close()
            
def saveSettings_2(key, value):
    i=-1
    if key in keyNames_2:
        i=keys_2.index(key)
        key=keys_2[i]
    if key in ("1","2","3","4","5"):
        with open(appPath+"/snmp.json","r")as f:
            json_str=f.read()
            edition=json.loads(json_str)
        if edition["snmp edition"]=="2":
            key=keys_2[int(key)-1]
        if edition["snmp edition"]=="3":
            if key=="1":
                key=keys_2[int(key)-1]
            else:
                key=keys_2[int(key)]
    if value != snmp[key]:
            snmp[key] = value
            fd = open(appPath+"/snmp.json", "w")
            fd.write(json.dumps(snmp))
            os.fsync(fd)
            fd.close()
    printConfig(1)
    
def getSettings(key):
    value = ""
    i=-1
    if key in keyNames:
        i=keyNames.index(key)
        key=keys[i]
    if key in config:
        value = config[key]
    return value
    
def printHelp():
    print("upsMonitor config    view the settings")
    print("upsMonitor view      view the state")
    print("upsMonitor start     start monitor")
    print("upsMonitor kill      stop monitor")
    print("upsMonitor config 1=snmp     set the agreement (Modbus or snmp)")
    print("upsMonitor config 2=127.0.0.1     set the snmp ip")
    print("upsMonitor config 6=\"shutdown -h now\"     set the shutdown cmd")

def upsMonitor():
    dataProcess(0)

def initCfg(cfg):
    toWrite = 0
    if os.path.exists(appPath+"/config.json"):
        cfg=json.loads(open(appPath+"/config.json","r").read())
        if not cfg:
            cfg=[]
    for key in keys:
        if key not in cfg:
            i=keys.index(key)
            cfg[key] = defConfigValue[i]
            toWrite = 1
    if toWrite:
        fd = open(appPath+"/config.json", "w")
        fd.write(json.dumps(cfg))
        os.fsync(fd)
        fd.close()
    return cfg
     
def initsnmp(s):
    toWrite = 0
    if os.path.exists(appPath+"/snmp.json"):
        s=json.loads(open(appPath+"/snmp.json","r").read())
        if not s:
            s=[]
    for key in keys_2:
        if key not in s:
            i=keys_2.index(key)
            s[key] = defsnmpValue[i]
            toWrite = 1
    if toWrite:
        fd = open(appPath+"/snmp.json", "w")
        fd.write(json.dumps(s))
        os.fsync(fd)
        fd.close()
    return s  
    
def snmpget(ip,ro,oid):
    from pysnmp.entity.rfc3413.oneliner import cmdgen
    cg = cmdgen.CommandGenerator() ##获得CommandGenerator对象
    errorIndication, errorStatus, errorIndex, varBinds = cg.getCmd(
      #0代表v1,1代表v2c 
    cmdgen.CommunityData(ro,ro, 1),  ##社区信息，my-agent ,public 表示社区名,1表示snmp v2c版本，0为v1版本
    cmdgen.UdpTransportTarget((ip, 161)),##这是传输的通道，传输到IP 192.168.70.237, 端口 161上(snmp标准默认161 UDP端口)
    oid ##传送的OID,个人认为MIB值
    )
   
    if errorIndication:
        print("Status:"+str(errorIndication))
    elif errorStatus:
        print(errorStatus)
    #print (str(varBinds[0][1])) ##varBinds返回是一个stulp，含有MIB值和获得值
    #print(varBinds[0])
    else: 
        return varBinds

def snmpv2_getbulk(ip, community, oid, count=25, port=161):
    from pysnmp.entity.rfc3413.oneliner import cmdgen
    cmd_gen = cmdgen.CommandGenerator()
    error_indication, error_status, error_index, var_bind_table = cmd_gen.bulkCmd(
        cmdgen.CommunityData(community),  # 配置community
        cmdgen.UdpTransportTarget((ip, port)),  # 配置IP地址和端口号
        0, count,  # 0为non-repeaters 和  25为max-repetitions(一个数据包中最多25个条目，和显示无关)
        oid,  # OID
    )
    # 错误处理
    # if error_indication:
        # print(error_indication)
    # elif error_status:
        # print(error_status)
    result = []
    # varBindTable是个list，元素的个数可能有好多个。它的元素也是list，这个list里的元素是ObjectType，个数只有1个。
    for var_bind_table_row in var_bind_table:
        for item in var_bind_table_row:
            result.append((item.prettyPrint().split("=")[0].strip(), item.prettyPrint().split("=")[1].strip()))
    return result

def get_all_info(ip, ro, newtime):

    if snmpget(ip,ro, ".1.3.6.1.2.1.33.1.2.5.0")!=None:
        #电池电压
        upsBatteryVoltage =str(float(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.2.5.0")[0][1])/10)
        #print(upsBatteryVoltage)
        
        #电池电流
        upsBatteryCurrent =str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.2.6.0")[0][1])
        #print(upsBatteryCurrent)
        
        #电池温度
        upsBatteryTemperature=str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.2.7.0")[0][1])
     
        #输入频率
        upsInputFrequency = str(float(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.3.3.1.2", count=25, port=161)[0][1])/10)
        #print(upsInputFrequency)
        
        #输入电压
        upsInputVoltage=str(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.3.3.1.3", count=25, port=161)[0][1])
        #print(upsInputVoltage)
        
        #输出频率
        upsOutputFrequency=str(float(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.4.2.0")[0][1])/10)
        #print(upsOutputFrequency)
        
        #输出电压
        upsOutputVoltage=str(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.4.4.1.2", count=25, port=161)[0][1])
        #print(upsOutputVoltage)
        
        #输出负载百分比
        #upsOutputPercentLoad=str(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.4.4.1.5", count=25, port=161)[0][1])
        #print(upsOutputPercentLoad)
        
        #旁路频率
        upsBypassFrequency=str(float(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.5.1.0")[0][1])/10)
        #print(upsBypassFrequency)
        
        #旁路电压
        upsBypassVoltage=str(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.5.3.1.2", count=25, port=161)[0][1])
        #print(upsBypassVoltage)
        
        #报警出现
        #upsAlarmsPresent=str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.6.1.0")[0][1])
        #print(upsAlarmsPresent)
        
        #配置输入电压
        upsConfigInputVoltage=str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.9.1.0")[0][1])
        #print(upsConfigInputVoltage)
        
        #配置输入频率
        upsConfigInputFreq=str(float(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.9.2.0")[0][1])/10)
        #print(upsConfigInputFreq)
        
        #配置输出电压
        upsConfigOutputVoltage=str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.9.3.0")[0][1])
        #print(upsConfigOutputVoltage)
        
        #配置输出频率
        upsConfigOutputFreq=str(float(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.9.4.0")[0][1])/10)
        #print(upsConfigOutputFreq
        
        #告警出现
        upsAlarmsPresent=str(snmpget(ip,ro, ".1.3.6.1.2.1.33.1.6.1.0")[0][1])
        #print(upsAlarmsPresent)
    
        all_info_dict={}
        
        all_info_dict.update({'upsBatteryVoltage':upsBatteryVoltage})
        all_info_dict.update({'upsBatteryCurrent':upsBatteryCurrent})
        all_info_dict.update({'upsBatteryTemperature':upsBatteryTemperature})
        all_info_dict.update({'upsInputFrequency':upsInputFrequency})
        all_info_dict.update({'upsInputVoltage':upsInputVoltage})
        all_info_dict.update({'upsOutputFrequency':upsOutputFrequency})
        all_info_dict.update({'upsOutputVoltage':upsOutputVoltage})
        all_info_dict.update({'upsBypassFrequency':upsBypassFrequency})
        all_info_dict.update({'upsBypassVoltage':upsBypassVoltage})
        all_info_dict.update({'upsConfigInputVoltage':upsConfigInputVoltage})
        all_info_dict.update({'upsConfigInputFreq':upsConfigInputFreq})
        all_info_dict.update({'upsConfigOutputVoltage':upsConfigOutputVoltage})
        all_info_dict.update({'upsConfigOutputFreq':upsConfigOutputFreq})
        all_info_dict.update({'upsAlarmsPresent':upsAlarmsPresent})
        
        
        if upsAlarmsPresent!="0":
         #print("报错了")  
        #告警信息
         upsAlarmDescr=snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.6.2.1.2", count=25, port=161)
         for k in range(len(upsAlarmDescr)):
          for i,j in upsWellKnownAlams.items():
           if upsAlarmDescr[k][1]==i:
            all_info_dict.update({'upsAlarm(s)':j})
         #all_info_dict.update({'upsAlarmDescr':upsAlarmDescr})
         
        
        print("snmp_v1&v2")
        #print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
        for i,j in all_info_dict.items():
            print(i+" : "+j)
            if(viewMode==0):
             SnmpLog("%s--%s\n\r" % (newtime,(i+" : "+j)))
             #datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        #if upsAlarmsPresent=="0":
            #print("Status:Normal")
        print("Status:Normal")
        if upsAlarmsPresent!="0":
            for i in range(len(upsAlarmDescr)):
                if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.6") :
                    while True:
                     # for i in range(len(upsAlarmDescr)):
                      # if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.9") :
                       ACShutdownTime = int(getSettings(
                        "ShutDown Delay for Ac Power Failed(s)"))
                       curTime = time()
                       LastTime = ACShutdownTime - curTime + preTime
                       if LastTime <= 0:
                         LastTime = 0
                         if not viewMode:
                            snmpshutDownSystem()
            
                if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.3") :
                    while True:
                       BatteryLowSysShutDown = int(getSettings(
                        "ShutDown Delay for Battery Low(s)"))
                       curTime = time()
                       BatLowLastTime = BatteryLowSysShutDown - curTime + batteryLowTime
                       if BatLowLastTime <= 0:
                         BatLowLastTime = 0
                         if not viewMode:
                            snmpshutDownSystem()
                    #print("Status:Warning")
             
     
def snmpv3_get(ip,user,hash_key,cry_key,oid):
    
    iterator = getCmd(
        SnmpEngine(),
        UsmUserData(user,hash_key,cry_key,#第一个为snmp用户名，第二个为认证密码，第三个为加密密码
                    authProtocol=usmHMACSHAAuthProtocol,#认证方式
                    privProtocol=usmDESPrivProtocol),#认证密码
        UdpTransportTarget((ip, 161)),
        ContextData(),
        ObjectType(ObjectIdentity(oid))
        #ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))
    )

    errorIndication, errorStatus, errorIndex, varBinds = next(iterator)

    if errorIndication:
        print("Status:"+str(errorIndication))

    elif errorStatus:
        print('%s at %s' % (errorStatus.prettyPrint(),
                            errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
    else:
        return varBinds[0][1]
		
def snmpv3_bulk(ip,user,hash_key,cry_key,oid):
    
    iterator = bulkCmd(
        SnmpEngine(),
        UsmUserData(user,hash_key,cry_key,#第一个为snmp用户名，第二个为认证密码，第三个为加密密码
                    authProtocol=usmHMACSHAAuthProtocol,#认证方式
                    privProtocol=usmDESPrivProtocol),#认证密码
        UdpTransportTarget((ip, 161)),
        ContextData(),
        0,25,
        ObjectType(ObjectIdentity(oid))
        # ObjectType(ObjectIdentity('SNMPv2-MIB', 'sysDescr', 0))
    )

    errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
    if errorIndication:
        print(errorIndication)

    elif errorStatus:
        print('%s at %s' % (errorStatus.prettyPrint(),errorIndex and varBinds[int(errorIndex) - 1][0] or '?'))
    else:
        return varBinds
		
def snmpv3_get_all_info(ip,user,hash_key,cry_key,newtime):
   if snmpv3_get(ip,user,hash_key,cry_key,".1.3.6.1.2.1.33.1.2.5.0")!=None:
    #电池状态
    upsbatterystatus=str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.2.1.0"))
    #print(upsbatterystatus)
    
    #电池电压
    upsBatteryVoltage =str(float(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.2.5.0"))/10)
    #print(upsBatteryVoltage)
    
    #电池电流
    upsBatteryCurrent =str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.2.6.0"))
    #print(upsBatteryCurrent)
    
    #电池温度
    upsBatteryTemperature=str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.2.7.0"))
 
    #输入频率
    upsInputFrequency = str(float(snmpv3_bulk(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.3.3.1.2")[0][1])/10)
    #print(upsInputFrequency)
    
    #输入电压
    upsInputVoltage=str(snmpv3_bulk(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.3.3.1.3")[0][1])
    #print(upsInputVoltage)
    
    #输出频率
    upsOutputFrequency=str(float(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.4.2.0"))/10)
    #print(upsOutputFrequency)
    
    #输出电压
    upsOutputVoltage=str(snmpv3_bulk(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.4.4.1.2")[0][1])
    #print(upsOutputVoltage)
    
    #输出负载百分比
    #upsOutputPercentLoad=str(snmpv2_getbulk(ip, ro, ".1.3.6.1.2.1.33.1.4.4.1.5", count=25, port=161)[0][1])
    #print(upsOutputPercentLoad)
    
    #旁路频率
    upsBypassFrequency=str(float(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.5.1.0"))/10)
    #print(upsBypassFrequency)
    
    #旁路电压
    upsBypassVoltage=str(snmpv3_bulk(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.5.3.1.2")[0][1])
    #print(upsBypassVoltage)
    
    #报警出现
    upsAlarmsPresent=str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.6.1.0"))
    #print(upsAlarmsPresent)
    
    #配置输入电压
    upsConfigInputVoltage=str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.9.1.0"))
    #print(upsConfigInputVoltage)
    
    #配置输入频率
    upsConfigInputFreq=str(float(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.9.2.0"))/10)
    #print(upsConfigInputFreq)
    
    #配置输出电压
    upsConfigOutputVoltage=str(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.9.3.0"))
    #print(upsConfigOutputVoltage)
    
    #配置输出频率
    upsConfigOutputFreq=str(float(snmpv3_get(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.9.4.0"))/10)
    #print(upsConfigOutputFreq)
    
    all_info_dict={}
    all_info_dict.update({'upsbatterystatus':upsbatterystatus})
    all_info_dict.update({'upsBatteryVoltage':upsBatteryVoltage})
    all_info_dict.update({'upsBatteryCurrent':upsBatteryCurrent})
    all_info_dict.update({'upsBatteryTemperature':upsBatteryTemperature})
    all_info_dict.update({'upsInputFrequency':upsInputFrequency})
    all_info_dict.update({'upsInputVoltage':upsInputVoltage})
    all_info_dict.update({'upsOutputFrequency':upsOutputFrequency})
    all_info_dict.update({'upsOutputVoltage':upsOutputVoltage})
    #all_info_dict.update({'upsOutputPercentLoad':upsOutputPercentLoad})
    all_info_dict.update({'upsBypassFrequency':upsBypassFrequency})
    all_info_dict.update({'upsBypassVoltage':upsBypassVoltage})
    #all_info_dict.update({'upsAlarmsPresent':upsAlarmsPresent})
    all_info_dict.update({'upsConfigInputVoltage':upsConfigInputVoltage})
    all_info_dict.update({'upsConfigInputFreq':upsConfigInputFreq})
    all_info_dict.update({'upsConfigOutputVoltage':upsConfigOutputVoltage})
    all_info_dict.update({'upsConfigOutputFreq':upsConfigOutputFreq})
    if upsAlarmsPresent!="0":
     #print("报错了")  
    #告警信息
     upsAlarmDescr=snmpv3_bulk(ip,user,hash_key,cry_key, ".1.3.6.1.2.1.33.1.6.2.1.2")
     for k in range(len(upsAlarmDescr)):
      for i,j in upsWellKnownAlams.items():
       if str(upsAlarmDescr[k][1])==i:
        all_info_dict.update({'upsAlarm(s)':j})
     #all_info_dict.update({'upsAlarmDescr':upsAlarmDescr})
    print("snmp_v3")
    #print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
    for i,j in all_info_dict.items():
        print(i+" : "+j)
        if(viewMode==0):
         SnmpLog("%s--%s\n\r" % (newtime,(i+" : "+j)))
         #datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    #if upsAlarmsPresent=="0":
        #print("Status:Normal")
    if upsAlarmsPresent!="0":
            for i in range(len(upsAlarmDescr)):
                if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.6") :
                    while True:
                     # for i in range(len(upsAlarmDescr)):
                      # if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.9") :
                       ACShutdownTime = int(getSettings(
                        "ShutDown Delay for Ac Power Failed(s)"))
                       curTime = time()
                       LastTime = ACShutdownTime - curTime + preTime
                       if LastTime <= 0:
                         LastTime = 0
                         if not viewMode:
                            snmpshutDownSystem()
            
                if(upsAlarmDescr[i][1]=="1.3.6.1.2.1.33.1.6.3.3") :
                    while True:
                       BatteryLowSysShutDown = int(getSettings(
                        "ShutDown Delay for Battery Low(s)"))
                       curTime = time()
                       BatLowLastTime = BatteryLowSysShutDown - curTime + batteryLowTime
                       if BatLowLastTime <= 0:
                         BatLowLastTime = 0
                         if not viewMode:
                            snmpshutDownSystem()
                    #print("Status:Warning")
    print("Status:Normal")    
        
#第一个参数是一个可以返回时间戳的函数，第二个参数可以在定时未到达之前阻塞。
s = sched.scheduler(time,sleep)
#被周期性调度触发的函数
#enter四个参数分别为：间隔事件、优先级（用于同时间到达的两个事件同时执行时定序）、被调用触发的函数，给他的参数（注意：一定要以tuple给如，如果只有一个参数就(xx,)）
def perform_V2(inc):
  s.enter(inc,0,perform_V2,(inc,))
  ip = getSettings("Ip Address")
  #viewMode=1
  #viewMode查看模式不会记录
  print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  newtime=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  with open(appPath+"/snmp.json","r")as a:
             json_str=a.read()
             agree=json.loads(json_str)
             get_all_info(ip,agree["community"],newtime)
             print("")

def mymain_V2(inc=10):
  s.enter(0,0,perform_V2,(inc,))
  s.run()
  
def perform_V3(inc):
  s.enter(inc,0,perform_V2,(inc,))
  ip = getSettings("Ip Address")
  #viewMode=1
  #viewMode查看模式不会记录
  print(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  newtime=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  with open(appPath+"/snmp.json","r")as a:
             json_str=a.read()
             agree=json.loads(json_str)
             snmpv3_get_all_info(ip,agree["username"],agree["userpassword"],agree["privacy protection password"],newtime)
             print("")
def mymain_V3(inc=10):
  s.enter(0,0,perform_V3,(inc,))
  s.run()

def printsnmphelp():
  with open(appPath+"/snmp.json","r")as f:
             json_str=f.read()
             edition=json.loads(json_str)
             if edition["snmp edition"]=="2":
                   print("")
                   print("example:upsMonitor snmp 1=2")
                   print("        upsMonitor snmp 2=eastups")
                  
             if edition["snmp edition"]=="3":
                   print("")
                   print("example:upsMonitor snmp 1=3")
                   print("        upsMonitor snmp 2=admin")
                   print("        upsMonitor snmp 3=12345678")
                   print("        upsMonitor snmp 4=12345678")
                   
if __name__ == '__main__':
    if not os.path.exists(appPath):
        os.makedirs(appPath)
    config = initCfg(config)
    snmp = initsnmp(snmp)
    if len(sys.argv) == 2:
        if sys.argv[1] == "start":
            open(appPath+"/pid","w").write(str(os.getpid()))
            upsMonitor()
        if sys.argv[1] == "config":
            printConfig(1)
            print("")
        if sys.argv[1] == "kill":
            if os.path.exists(appPath+"/pid"):
                pid=open(appPath+"/pid","r").read()
                os.system("kill -9 %s"%pid)
        if sys.argv[1] == "help":
            printHelp()
        if sys.argv[1] == "view":
            dataProcess(viewMode) 
            #print(get_all_info('192.168.163.196', 'eastups'))
    elif len(sys.argv) == 3:
        tmp = sys.argv[2].split("=")
        if len(tmp) == 2:
           if sys.argv[1] == "config":
            saveSettings(tmp[0], tmp[1])
            printConfig(1)
           if sys.argv[1] == "snmp":
            saveSettings_2(tmp[0], tmp[1])
    elif len(sys.argv) > 3:
      tmp=''
      for i in range(2,len(sys.argv)):
        tmp = tmp+sys.argv[i]
      tmp = tmp.split("=")
      if len(tmp) == 2:
         if sys.argv[1] == "config":
           saveSettings(tmp[0], tmp[1])
           printConfig(1)
         if sys.argv[1] == "snmp":
           saveSettings_2(tmp[0], tmp[1])
    # else:
        # printHelp()
    