Exemple #1
0
class Connection(object):
    def __init__(self):
        logging.basicConfig(filename="/home/pi/ZeMoCode/Data/ZeMo.log",
                            level=logging.INFO)
        self.screen = Screen()
        self.eth0 = self.get_ip("eth0", 3)
        self.wlan0 = self.get_ip("wlan0", 3)
        registered = False
        try:
            with open("/home/pi/ZeMoCode/account") as f:
                acnt = f.read()
                self.account = acnt.strip('\n')
                self.logInfo("ACCOUNT " + self.account)
        except:
            # Occurs if the account file did not create properly from SetupZeMo.sh file
            self.account = "NULL_ACCOUNT_NAME"
        if self.account is "NULL_ACCOUNT_NAME":
            self.screen.drawMessage("No Account Found, Please Retry")
            self.logInfo("No account found")
            time.sleep(30)
        self.piName = socket.gethostname()
        try:
            # Tries to load an existing account
            self.accountJSON = json.load(
                open('/home/pi/ZeMoCode/account.json'))
            self.secret = self.accountJSON["secret"]
            try:
                self.jsonConfig = self.getConfigData()
            except:
                self.logInfo("Did not grab config file")
            if self.secret is "none":
                # Loops until registration is completed
                while registered is False:
                    registered = self.register()
        except Exception as e:
            # Registers if no existing account is found
            self.secret = "none"
            # Loops until registration is completed
            while registered is False:
                registered = self.register()
        self.screen.drawImage("logo.png", self.screen.background.get_rect(),
                              223, 57)

    # Resets account info
    def resetAccount(self):
        try:
            os.remove("/home/pi/ZeMoCode/account.json")
        except Exception as e:
            self.logError(e)
        self.account = ""
        self.secret = ""
        self.piName = ""

    def getaccountJSON(self):
        return self.accountJSON

    def getJSONconfig(self):
        return self.jsonConfig

    def getAccount(self):
        return self.account

    def getPiName(self):
        return self.piName

    def getSecret(self):
        return self.secret

    def getEth0(self):
        return self.eth0

    def getWlan0(self):
        return self.wlan0

    # Emails ip address
    def sendIP(self):
        message = "zfish1 is up and running at (wired, wireless): " + self.getWlan0(
        )
        self.sendEmail(message)

    # Emails the sensors that are not working
    def warning(self, sensors):
        message = "These sensors are not working: " + " ".join(
            sensors.getName())
        self.sendEmail(message)

    # Emails Log Data from pi
    def sendLogData(self, files):
        try:
            s1 = ""
            s3 = ""
            s4 = ""
            s2 = ""
            with open(files[0]) as f:
                s1 = f.read() + '\n'
            with open(files[1]) as f:
                s2 = f.read() + '\n'
            with open(files[2]) as f:
                s3 = f.read() + '\n'
            with open(files[3]) as f:
                s4 = f.read() + '\n'

            values = {
                "body":
                "Log Data",
                "attachments": [{
                    "filename": files[0],
                    "content": s1
                }, {
                    "filename": files[1],
                    "content": s2
                }, {
                    "filename": files[2],
                    "content": s3
                }, {
                    "filename": files[3],
                    "content": s4
                }]
            }
            url = 'https://zemoproject.org/notifications/' + self.account + '/' + self.piName
            params = json.dumps(values)

            bearer = 'Bearer ' + self.secret
            headers = {
                'content-type': 'application/json',
                'Authorization': bearer
            }
            req = requests.post(url=url, json=values, headers=headers)
            self.screen.drawMessage("Log Data Sent!")
            time.sleep(2)
        except Exception as e:
            self.logError(e)
            self.screen.drawMessage("Did not send email")
            time.sleep(2)

    # Returns the user settings from the website
    def getConfigData(self):
        try:
            url = 'https://zemoproject.org/settings/' + self.account + '/' + self.piName
            bearer = 'Bearer ' + self.secret
            headers = {
                'content-type': 'application/json',
                'Authorization': bearer
            }
            req = requests.get(url=url, headers=headers)
            return req.json()
        except Exception as e:
            self.logInfo("In getConfigData")
            self.logInfo("account: " + str(self.account))
            self.logInfo("piName: " + str(self.piName))
            self.logInfo("ip: " + str(self.getWlan0()))
            self.logError(e)

    # Sends the hourly readings
    def sendReadings(self, values):
        try:
            params = json.dumps(values).encode('utf8')
            emailEndPoint = "https://zemoproject.org/data/" + self.account + "/" + self.piName
            bearer = 'Bearer ' + self.secret
            req = urllib.request.Request(emailEndPoint,
                                         data=params,
                                         headers={
                                             'content-type':
                                             'application/json',
                                             'Authorization': bearer
                                         })
            response = urllib.request.urlopen(req)
        except Exception as e:
            self.logError(e)

    def sendEmail(self, message):
        try:
            values = {'body': message}

            params = json.dumps(values).encode('utf8')
            emailEndPoint = 'https://zemoproject.org/notifications/' + self.account + '/' + self.piName
            bearer = 'Bearer ' + self.secret
            req = urllib.request.Request(emailEndPoint,
                                         data=params,
                                         headers={
                                             'content-type':
                                             'application/json',
                                             'Authorization': bearer
                                         })
            response = urllib.request.urlopen(req)
        except Exception as e:
            self.logError(e)

    # Sends an email of the probes out of range with the associated data
    def sendOutofRange(self, sensors):
        try:
            compiledMsg = "These sensors are out of range:"
            message = ""
            for probe in sensors:
                message = message + "\n" + probe.getName(
                ) + ": " + probe.getData()
            compiledMsg = compiledMsg + message + " \nThe data here includes the trimmed readings."
            values = {'body': compiledMsg}

            params = json.dumps(values).encode('utf8')
            emailEndPoint = 'https://zemoproject.org/notifications/' + self.account + '/' + self.piName
            bearer = 'Bearer ' + self.secret
            req = urllib.request.Request(emailEndPoint,
                                         data=params,
                                         headers={
                                             'content-type':
                                             'application/json',
                                             'Authorization': bearer
                                         })
            response = urllib.request.urlopen(req)
        except Exception as e:
            self.logError(e)

    # Sends registration info, pi should appear on website afterwards
    def sendRegister(self):
        try:
            values = {
                "account": self.account,
                "name": self.piName,
                "ip_address": self.getWlan0()
            }

            url = 'https://zemoproject.org/register'
            params = json.dumps(values)
            headers = {'content-type': 'application/json'}
            req = requests.post(url=url, json=values, headers=headers)
            sec = req.json()
            self.secret = sec["secret"]
            return True
        except:
            self.logInfo(str(values))
            self.logInfo("rec: " + str(req))
            return False

    # Draws the registration screen and responds to user input
    def screenRegisterResend(self):
        resend = self.screen.register_screen()
        if resend is False:
            self.screen.drawMessage("Attempting to Register")
        elif resend is True:
            self.sendRegister()
            self.screen.drawMessage("New Request Sent")
        time.sleep(2)

    # Waits for user to push accept on the website
    def waitForAccept(self):
        try:
            self.jsonConfig = self.getConfigData()
            if self.jsonConfig is None or self.secret is "none":
                self.screenRegisterResend()
                return False
            return True
        except:
            self.screenRegisterResend()
            return False

    # Registers pi
    def register(self):
        try:
            self.sendRegister()
            accepted = False
            while accepted is False:
                accepted = self.waitForAccept()
            cfg = {
                "secret": self.secret,
                "account": self.account,
                "piName": self.piName
            }
            with open("/home/pi/ZeMoCode/account.json", "w") as g:
                json.dump(cfg, g)
            self.accountJSON = json.load(
                open('/home/pi/ZeMoCode/account.json'))
            self.screen.canvas.fill((0, 0, 0))
            self.screen.drawImage("logo.png",
                                  self.screen.background.get_rect(), 223, 57)
            return True
        except Exception as e:
            self.logInfo("In Register Function")
            self.logInfo("account: " + str(self.account))
            self.logInfo("piName: " + str(self.piName))
            self.logInfo("ip: " + str(self.getWlan0()))
            self.logError(e)
            self.screen.drawMessage("Failed to grab Settings")
            time.sleep(2)
            self.screen.drawMessage("Make sure to \"Accept\"")
            time.sleep(2)
            return False

    # Returns IP address of pi
    def get_ip(self, network, countdown):
        try:
            countdown = countdown - 1
            if (countdown is not 0):
                s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                return socket.inet_ntoa(
                    fcntl.ioctl(
                        s.fileno(), 0x8915,
                        struct.pack('256s', bytes(network[:15],
                                                  'utf-8')))[20:24])
        except:
            self.get_ip(network, countdown)

    # Logging errors
    def logError(self, info):
        try:
            logging.exception(str(info))
        except:
            pass

    # Logging Info
    def logInfo(self, info):
        try:
            logging.info(str(info))
        except:
            pass
Exemple #2
0
class App(object):
    def __init__(self):
        print("ZeMo is Running")
        self.screen = Screen()
        self.screen.drawImage("logo.png", self.screen.background.get_rect(), 223, 57)
        self.conn = Connection()
        self.done = False
        self.takeReadFlag = True
        self.readingNow = False
        self.waitTime = 0
        jsonFile = self.conn.getJSONconfig()
        self.daysToKeep = jsonFile["settings"]["days"]
        self.readsPerDay = jsonFile["settings"]["reads"]
        self.timeList = []
        piName = self.conn.getPiName()
        self.phSensor = PH(jsonFile, piName, self.screen)
        self.condSensor = Conductivity(jsonFile, piName, self.screen)
        self.dOSensor = DissolvedOxygen(jsonFile, piName, self.screen)
        self.tempSensor = Temperature(jsonFile, piName, self.screen)
        self.sensorList = []
        self.sensorList.append(self.tempSensor)
        self.sensorList.append(self.condSensor)
        self.sensorList.append(self.phSensor)
        self.sensorList.append(self.dOSensor)
        for sensor in self.sensorList:
            sensor.takeRead(self.conn)
        self.t2 = Thread(target=App.checkTime_loop, args=(self,))
        self.t2.start()
        self.update_reads_per_day()        

    def checkQuit(self, eventType):
        try:
            if eventType == pg.QUIT or pg.key.get_pressed()[pg.K_ESCAPE]:
                self.done = True
                self.screen.quit()
                sys.exit()
        except Exception as e:
            self.conn.logError(e)

	# Checks the values and emails if values are out of range, the ooR occurs here
    def takeReads_checkAlarms(self):
        try:
            sensors = []
            jsonFile = self.conn.getConfigData()
            self.daysToKeep = jsonFile["settings"]["days"]
            self.readsPerDay = jsonFile["settings"]["reads"] 
            self.update_reads_per_day()           
            piName = self.conn.getPiName()        
            for sensor in self.sensorList:
                sensor.refresh(jsonFile, piName)            
                sensor.takeRead(self.conn)
                read = float(sensor.getCurrRead())
                if read > float(sensor.getHighRange()) or read < float(sensor.getLowRange()):
                    sensors.append(sensor)
            if len(sensors) > 0:
                self.conn.sendOutofRange(sensors)
        except Exception as e:
            self.conn.logError(e)

    # Updates the list of times checked in the CheckTime() function
    def update_reads_per_day(self):
        try:
            if int(self.readsPerDay) > 96:
                self.readsPerDay = "96"
            self.timeList = []
            hours = 24 / int(self.readsPerDay)
            i = 0.00
            j = 0.00
            while i < 24:
                i = hours + i
                if i < 24:
                    addHour = int(i)
                    y = i % 1
                    j = (y * 60) / 100
                    addTime = addHour + round(j, 2)
                    addThis = str(round(addTime, 2))
                    self.timeList.append(addThis)
        except Exception as e:
            self.conn.logError(e)

    # A constantly running loop that has an individual thread
    # Checks the time for taking automated reads
    def checkTime_loop(self):
        while not self.done:
            try:
                currMin = datetime.now().minute
                currHour = datetime.now().hour
                if int(currHour) < 1:
                    currHour = "0"
                else:
                    currHour = str(round(int(currHour), 0))
                if currMin > 9:
                    uCurrTime = currHour + "." + str(round(currMin, 0))
                elif currMin < 1:
                    uCurrTime = currHour + ".0"
                else:
                    uCurrTime = currHour + ".0" + str(round(currMin, 0))
                currTime = str(uCurrTime)
                #potential increase to speed, try:
                #self.timeList.index(currTime)
                if(currTime in self.timeList and self.takeReadFlag is True) or currTime == "0.0":  
                    self.takeReadFlag = False
                    self.waitTime = currMin + 1
                    if(self.waitTime > 59):
                        self.waitTime = 0
                    self.readingNow = True
                    try:
                        takingReads = Thread(target=App.taking_reads_loop, args=(self,))
                        takingReads.start()
                    except Exception as e:
                        self.conn.logError(e)
                        self.screen.drawMessage("Taking Reads")
                    self.takeReads_checkAlarms()
                    pg.event.clear()
                    self.readingNow = False
                    time.sleep(2)
                elif self.waitTime < int(currMin) and self.waitTime != 0:
                    self.takeReadFlag = True
            except Exception as e:
                self.conn.logError(e)
                self.readingNow = False

    # Advanced Settings
    def advanced_settings_event(self):
        try:
            while not self.done:
                if not self.readingNow:
                    self.screen.advanced_settings_event_screen()
                    pg.display.update()
                    pg.event.clear()
                    pg.event.wait()
                    if not self.readingNow:
                        for event in pg.event.get():
                            self.checkQuit(event.type)
                            if event.type == pg.MOUSEBUTTONDOWN:
                                button = self.screen.checkCollision(event.pos)
                                if button is 5:
                                    return
                                elif button is 1:
                                    files = []
                                    for item in self.sensorList:
                                        file2 = item.getFilename()[:-4]
                                        files.append(file2 + "_log.csv")
                                    self.conn.sendLogData(files)
                                    self.screen.drawMessage("Log Files Emailed")                                      
                                elif button is 2:
                                    for item in self.sensorList:
                                        item.deleteHistory()
                                    self.screen.drawMessage("Data removed")
                                    time.sleep(2)
                                    self.screen.drawMessage("Next sync will update graphs")
                                    time.sleep(2)
                                elif button is 3:
                                    #re-register - clears all the input data of piName, secret key, and account
                                    if self.screen.reregister() is True:
                                        self.conn.resetAccount()
                                        jsonFile = self.conn.getConfigData()
                                        piName = self.conn.getPiName()
                                        for sensor in self.sensorList:
                                            sensor.refresh(jsonFile, piName)
                                        self.screen.drawMessage("Re-download the software")
                                        time.sleep(4)
                                        self.done = True
                                    else:
                                        self.screen.advanced_settings_event_screen()
                                        pg.display.update()
                                elif button is 4:
                                    self.done = True
                                    return      
        except Exception as e:
            self.conn.logError(e)                                                     

    def settings_event(self):
        try:
            while not self.done:
                if not self.readingNow:
                    self.screen.settings_event_screen(self.conn.getEth0(), self.conn.getWlan0(),
                        self.readsPerDay, self.daysToKeep)
                    pg.display.update()
                    pg.event.clear()
                    pg.event.wait()
                    if not self.readingNow:
                        for event in pg.event.get():
                            self.checkQuit(event.type)
                            if event.type == pg.MOUSEBUTTONDOWN:
                                button = self.screen.checkCollision(event.pos)
                                if button is 5:
                                    return
                                elif button is 7:
                                    self.advanced_settings_event()
                                elif button is 2:
                                    #refresh all sensors
                                    jsonFile = self.conn.getConfigData()
                                    piName = self.conn.getPiName()
                                    for sensor in self.sensorList:
                                        sensor.refresh(jsonFile, piName)
        except Exception as e:
            self.conn.logError(e)


    # Screen shows "Taking Reads..."
    def taking_reads_loop(self):
        try:
            while(self.readingNow):
                self.screen.drawMessage("Taking Reads   ")
                pg.display.update()
                if(self.readingNow):
                    time.sleep(1)
                    self.screen.drawMessage("Taking Reads.  ")
                    pg.display.update()
                    if(self.readingNow):    
                        time.sleep(1)                  
                        self.screen.drawMessage("Taking Reads.. ")
                        pg.display.update()
                        if(self.readingNow):
                            time.sleep(1)
                            self.screen.drawMessage("Taking Reads...")
                            pg.display.update()
                            if(self.readingNow):
                                time.sleep(1)
                self.screen.canvas.fill((0,0,0))
            self.screen.canvas.fill((0,0,0))
        except Exception as e:
            self.conn.logError(e)

    # Update Probe
    def update_event(self, sensor):
        while not self.done:
            if not self.readingNow:
                try:
                    self.screen.update_event_screen(sensor)
                    pg.display.update()
                    pg.event.clear()
                    pg.event.wait()
                    if not self.readingNow:
                        for event in pg.event.get():
                                self.checkQuit(event.type)
                                if event.type == pg.MOUSEBUTTONDOWN:
                                    button = self.screen.checkCollision(event.pos)
                                    if button is 1:
                                        sensor.calibrate()
                                    elif button is 2:
                                        jsonFile = self.conn.getConfigData()
                                        piName = self.conn.getPiName()                                        
                                        sensor.refresh(jsonFile, piName)
                                    elif button is 5:
                                        return
                                    elif button is 8 or button is 4 or button is 3:
                                        try:
                                            self.readingNow = True
                                            takingReads = Thread(target=App.taking_reads_loop, args=(self,))
                                            takingReads.start()
                                            jsonFile = self.conn.getConfigData()
                                            piName = self.conn.getPiName()
                                            sensor.refresh(jsonFile, piName)                                              
                                            sensor.takeRead(self.conn)
                                            self.readingNow = False
                                        except:
                                            self.readingNow = False
                                        time.sleep(1)
                                        self.screen.update_event_screen(sensor)                                                                            
                except Exception as e:
                    self.conn.logError(e)

    # Switches between the event loops depending on button pressed  
    def main_event_loop(self):
            while not self.done:
                try:
                    if not self.readingNow:
                        self.screen.main_menu_screen(self.condSensor.getCurrRead(), 
                            self.dOSensor.getCurrRead(), self.phSensor.getCurrRead(), 
                            self.tempSensor.getCurrRead())
                        pg.display.update()
                        pg.event.clear()  
                        pg.event.wait()
                        if not self.readingNow:
                            for event in pg.event.get():
                                self.checkQuit(event.type)
                                if event.type == pg.MOUSEBUTTONDOWN:
                                    button = self.screen.checkCollision(event.pos)
                                    if button is 7:
                                        self.settings_event()
                                    elif button is 1:
                                        self.update_event(self.condSensor)
                                    elif button is 2:
                                        self.update_event(self.dOSensor)
                                    elif button is 3:
                                        self.update_event(self.phSensor)
                                    elif button is 4:
                                        self.update_event(self.tempSensor)
                except Exception as e:
                    self.conn.logError(e)