コード例 #1
0
class CO2_stat(object):
    """Code associated with the thermostat controller"""
    def __init__(self):
        self.logger = Logger("CO2_stat")
        self.logger.debug("initialize CO2 controller object")
        self._co2 = SCD30(self.logger)
        self._fan = Fan(self.logger)

    def check(self, co2=None, test=False):
        """Adjust the fan depending upon the CO2
               Args:
                   temp: optional test CO2
               Returns:
                   None
               Raises:
                   None
        """
        target_co2 = TARGET_CO2
        if co2 == None:
            co2, temp, rh = self._co2.get_data()
        msg = "{} {} {} {}".format("CO2:", co2, " Target CO2:", target_co2)
        # Get target temperature from file

        self.logger.info(msg)
        if co2 > target_co2:
            self._fan.set(Fan.ON)
        else:
            self._fan.set(Fan.OFF)
コード例 #2
0
ファイル: EC.py プロジェクト: webbhm/NerdFarm
class EC(object):

    GAIN = 1

    def __init__(self, logger=None):
        self._pin = 0  # ADS1115 Channel to use
        self._logger = logger
        if logger == None:
            self._logger = Logger("EC", Logger.INFO)
        # Create an ADS1115 ADC (16-bit) instance.
        self._adc = ADS1115(logger)

    def getEC(self):
        """Read the sensor value
           Args:
               None
           Returns:
               EC value as number between 0 and 32,000
           Raises:
               None
      """
        ec = self._adc.read_adc(self._pin, gain=self.GAIN)
        self._logger.info("{} {} {}: {}".format("EC pin", self._pin, "value",
                                                ec))
        return ec
コード例 #3
0
class Humidistat(object):
    """Code associated with the thermostat controller"""
    def __init__(self):
        self._logger = Logger("Humidistat")
        self._logger.setLevel(Logger.INFO)
        self._logger.debug("initialize Humidistat object")
        self._co2 = SCD30()
        self._humidifier = Humidifier()
        self._target_rh = 80

    def check(self, rh=None, test=False):
        """Adjust the fhumidifier depending upon the rh
               Args:
                   temp: optional test rh
               Returns:
                   None
               Raises:
                   None
        """
        if rh == None:
            co2, temp, rh = self._co2.get_data()
            msg = "{} {} {} {}".format("Humidity:", rh, " Target Humidity:",
                                       self._target_rh)
            self._logger.info(msg)
        if rh > self._target_rh:
            self._humidifier.set(Humidifier.OFF)
        else:
            self._humidifier.set(Humidifier.ON)
コード例 #4
0
ファイル: CouchHeartbeat.py プロジェクト: webbhm/NerdFarm
class CouchHeartbeat(object):
    """Heartbeat object    """

    logger = None

    def __init__(self):
        """Standard constructor
        Get and hold a Python logger
        """
        self._logger = Logger('CouchHeartbeat', Logger.INFO,
                              "/home/pi/MVP/logs/heartbeat.log")

    def check(self, port):
        """Ping the database
        Should return the welcome message
        Throws an exception if cannot make a connection to the database

        Args:
            port: port the database is communicating on
        Returns:
            None
        Raises:
            None
        """
        cmd = 'curl -X GET http://localhost:5984'
        ret = os.system(cmd)
        if ret == 0:
            self._logger.info('localhost Couch is Up')
        else:
            self._logger.error('Couch is Down')
            self.restart()

    def restart(self):
        """System restart (reboot)
        Args:
            None
        Returns:
            None
        Raises:
            None
        """
        cmd = 'sudo reboot'
        self.logger.warning('System restart: %s' % (cmd))
        os.system(cmd)
コード例 #5
0
class V_CO2(object):

    def __init__(self, logger=None):
        self._logger = logger
        if logger == None:
            self._logger = Logger("V_CO2", Logger.INFO)
        
        self._gdx = gdx()
        self._gdx.open_usb()
        #self._headers = self._gdx.enabled_sensor_info(self._gdx)
        self._headers = self._gdx.enabled_sensor_info()
        self._info = self._gdx.sensor_info()
        self._logger.info("Initialized V_CO2")
        sleep(20)  # wait 20 seconds to warm up
        
    def _exit_(self):
        self.close()
        
    def close(self):        
        self._gdx.stop()
        self._gdx.close()
        
       
    def info(self):
        # 0 = sensor number, 1 = description, 2 = units, 3 = incompatible sensors
        for info in self._info:
            sensor_number = info[0]
            sensor_description = info[1]  
            sensor_units = info[2]  
            incompatible_sensors = info[3]  
            print("sensor number = ", sensor_number)
            print("sensor description = ", sensor_description)
            print("sensor units = ", sensor_units)
            print("incompatible sensors = ", incompatible_sensors)
            print()
        print('End Sensor Info')            

    def read(self):
        self._gdx.select_sensors([1,2, 3])
        self._gdx.start(period=1000)
        for x in range(0, 6):
            data = self._gdx.read()
            print(data)
            
    def getData(self):
        self._gdx.select_sensors([1,2, 3])
        self._gdx.start(period=1000)
        data = self._gdx.read()
        if data is None:
            return None
        
        temp = data[0]
        humidity = data[1]
        co2 = data[2]
        return temp, humidity, co2
        
        
            
    def log(self):
        # isolate Sheet to this function
        # Note: this is a push data function 
        from G_AppendUtil import AppendUtil
        util = AppendUtil()
        # Pull data from all three channels co2, temp, humidity
        self._gdx.select_sensors([1,2,3])
        self._gdx.start(period=1000)
        while True:
            data = self._gdx.read()
            co2 = data[0]
            temp = data[1]
            hum = data[2]
            c_rec = ['Environment_Observation', '', 'Canopy', 'Air', 'CO2', "{:3.1f}".format(co2), 'ppm', 'Vernier', 'Success','']
            t_rec = ['Environment_Observation', '', 'Canopy', 'Air', 'Temperature', "{:3.1f}".format(temp), 'C', 'Vernier', 'Success','']
            h_rec = ['Environment_Observation', '', 'Canopy', 'Air', 'Humidity', "{:3.1f}".format(hum), '%', 'Vernier', 'Success','']
            util.save(c_rec)
            util.save(t_rec)
            util.save(h_rec)
            sleep(3)
            
            print(data)
コード例 #6
0
class LogShroom(object):
    def __init__(self, logger=None):
        """Create sensor object
           Args:
               None
           Returns:
               None
           Raises:
               None
        """
        self._logger = logger
        if logger == None:
            self._logger = Logger("LogShroom",
                                  Logger.INFO,
                                  file="/home/pi/MVP/logs/obsv.log")
        self._logger.debug("Initialize LogShroom")
        self._couch = CouchUtil(self._logger)
        # flag for testing
        self._test = False

    def log(self):
        """Routine to log all sensors
        Args:
            None
        Returns:
            None
        Raises:
            None
        """
        self.getSCD()

    def getSCD(self):
        """Record CO2 sensor (scd30)
            Generates co2, temperature and relative humidity
        Args:
            None
        Returns:
            None
        Raises:
            None
        """

        from scd30 import SCD30
        self._scd = SCD30(self._logger)
        self._logger.debug("In SCD30")
        try:
            co2, temp, rh = self._scd.get_data()

            status = 'Success'
            if self._test:
                status = 'Test'
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'CO2',
                "{:10.1f}".format(co2), 'ppm', 'scd30', status, ''
            ])
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'Temperature',
                "{:10.1f}".format(temp), 'Centigrade', 'scd30', status, ''
            ])
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'Humidity',
                "{:10.1f}".format(rh), 'Percent', 'scd30', status, ''
            ])
            self._logger.info("{} {:6.1f}, {} {:3.1f}, {} {:3.1f}".format(
                "EnvObsv-CO2:", co2, "Temp", temp, "Humidity:", rh))
        except Exception as e:
            status = 'Failure'
            if self._test:
                status = 'Test'
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'CO2', '', 'ppm',
                'scd30', status,
                str(e)
            ])
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'Temperature', '',
                'Centigrde', 'scd30', status, ''
            ])
            self._couch.saveList([
                'Environment_Observation', '', 'Top', 'Air', 'Humidity', '',
                'Percent', 'scd30', status, ''
            ])
            self._logger.debug("{} {}".format("EnvObsv-SCD30 Error:", e))
コード例 #7
0
ファイル: SI7021.py プロジェクト: webbhm/NerdFarm
class SI7021(object):
    def __init__(self, logger=None):

        self._addr = addr
        self._path = path
        self._logger = logger
        if logger == None:
            self._logger = Logger("SI7021", Logger.INFO,
                                  "/home/pi/MVP/logs/obsv.log")
        self._i2c = I2C(path, addr, self._logger)

    def calc_humidity(self, read):
        """Calculate relative humidity from sensor reading
           Args:
               read: the sensor value
           Returns:
               rh: calculated relative humidity
           Raises:
               None
      """
        rh = ((125.0 * read) / 65536.0) - 6.0
        return rh

    def calc_temp(self, read):
        """Calculate relative humidity from sensor reading
           Args:
               read: the sensor value
           Returns:
               tempC: calculated temperature in Centigrade
           Raises:
               None
      """
        tempC = ((175.72 * read) / 65536.0) - 46.85
        return tempC

    def get_tempC_prior(self):
        """Get the temperature from the prior humidity reading
           Args:
               None
           Returns:
               tempC: calculated temperature in Centigrade
           Raises:
               None
       """

        msgs = self._i2c.get_data([previous_temp], 0.03, 3)
        if msgs == None:
            return None
        else:
            value = self._i2c.bytesToWord(msgs[0].data[0], msgs[0].data[1])
            tempC = self.calc_temp(value)
            return tempC

    def get_humidity(self):
        """Get the humidity
           Args:
               None
           Returns:
               rh: calculated relative humidity
           Raises:
                None
       """
        msgs = self._i2c.get_data([rh_no_hold], 0.03, 2)
        value = self._i2c.bytesToWord(msgs[0].data[0], msgs[0].data[1])
        if value == None:
            return None
        else:
            rh = self.calc_humidity(value)
            return rh

    def get_tempC(self):
        """Get the temperature (new reading)
           Args:
               None
           Returns:
               tempC: calculated temperature in Centigrade
           Raises:
               None
       """
        msgs = self._i2c.get_data([temp_no_hold], 0.03, 3)
        value = self._i2c.bytesToWord(msgs[0].data[0], msgs[0].data[1])
        if value == None:
            return None
        else:
            return self.calc_temp(value)

    def get_rev(self):
        """Get the firmware revision number
           Args:
               None
           Returns:
               rev: coded revision number
           Raises:
               None
       """
        self._logger.info("\nGet Revision")
        #       msgs = self._i2c.get_msg([firm_rev_1_1, firm_rev_1_2], 3)
        msgs = self._i2c.get_data([firm_rev_1_1, firm_rev_1_2], 0.03, 3)
        # Need to test, may error out on some conditions
        if not ((msgs is None) or (msgs[0].data is None)):
            rev = msgs[0].data[0]
            if rev == 0xFF:
                self._logger.info("version 1.0")
            elif rev == 0x20:
                self._logger.info("version 2.0")
            else:
                self._logger.error("Unknown")
        else:
            self._logger.error("No Revision Data Available")
            return rev

    def get_id1(self):
        """Print the first part of the chips unique id
           Args:
               None
           Returns:
               None
           Raises:
                None
       """
        self._logger.info("\nGet ID 1")
        try:
            msgs = self._i2c.get_data([read_id_1_1, read_id_1_2], 0.05, 4)
            ret = msgs[0].data
            for data in ret:
                self._logger.info("ID: " + str(hex(data)))
        except Exception as e:
            self._logger.error("Error getting msgs " + str(e))

    def get_id2(self):
        """Print the second part of the chips unique id
           The device version is in SNA_3
           Args:
               None
           Returns:
               None
           Raises:
               None
       """

        self._logger.info("\nGet ID 2")
        msgs = self._i2c.get_data([read_id_2_1, read_id_2_2], 0.05, 4)
        ret = msgs[0].data
        for data in ret:
            self._logger.info("ID" + str(hex(data)))
        sna3 = msgs[0].data[0]
        if sna3 == 0x00:
            self._logger.info("Device: Engineering Sample")
        elif sna3 == 0xFF:
            self._logger.info("Device: Engineering Sample")
        elif sna3 == 0x14:
            self._logger.info("Device: SI7020")
        elif sna3 == 0x15:
            self._logger.info("Device: SI7021")
        else:
            self._logger.error("Unknown")

    def reset(self):
        """Reset the device
           Args:
               None
           Returns:
               None
           Raises:
               None
       """

        self._logger.info("\nReset")
        rev_1 = self._i2c.msg_write([reset_cmd])
        self._logger.info("Reset: " + str(rev_1))
コード例 #8
0
class Reservoir:

    FULL = 0
    EMPTY = 1
    OK = 2

    vol_per_mm = 0.3785  # estimate 1 gal per 10 mm, this is reservoir specific
    vol_per_sec = 0.3785  # estimate 100 ml per sec, this is reservoir specific

    def __init__(self):
        '''Get distances for determining reservoir levels'''
        self.res = {'full': full_ec, 'empty': empty_ec, 'timeout': timeout}
        self._activity_type = 'Agronomic_Activity'
        self._logger = Logger('LogReservoir', Logger.INFO)
        self._persist = Persistence(self._logger)
        self._logger.detail("Reservoir Initialized")
        # flag for testing
        self._test = False

    def getStatus(self):
        "Logic for calling the reservoir full"
        self._logger.detail("In getStatus")
        ec = self.getEC()
        if ec <= full_ec:
            self._logger.debug("{}, {}, {:10.1f}".format(
                "Reservoir Full", EC, ec))
            return Reservoir.FULL, ec
        elif ec >= empty_ec:
            self._logger.debug("{}, {}, {:10.1f}".format(
                "Reservoir Empty", EC, ec))
            return Reservoir.EMPTY, ec
        else:
            self._logger.debug("{}, {}, {:10.1f}".format(
                "Reservoir not Empty", EC, ec))
            return Reservoir.OK, ec

    def isFull(self):
        self._logger.detail("In isFull")
        status, ec = self.getStatus()
        if status == Reservoir.FULL:
            return True
        else:
            return False

    def getEC(self):
        '''Get EC reading'''
        self._logger.detail("In getEC")
        snsr = EC(self._logger)
        return snsr.getEC()

    def fill(self, test=False):
        ''' Routine to control re-filling of the reservoir'''
        self._logger.detail("{}".format("In Fill"))
        start_ec = self.getEC()
        start_t = time.time()
        pump = Pump()
        pump.on()
        # Loop till filled or times out
        while (not self.isFull()) and self.isFilling(start_t):
            self._logger.detail("{}".format("In Fill Loop"))
        self._logger.detail("{}".format("Exit Fill Loop, close solenoid"))
        # Close valve
        pump.off()
        # Calculate amount filled
        stop_t = time.time()
        stop_ec = self.getEC()
        dif_t = stop_t - start_t
        volume = dif_t * self.vol_per_sec
        self._logger.detail("{}".format("Exit Fill"))

        return volume

    def isFilling(self, start_time, test=False):
        '''Check that actually filling: the distance is actually changing'''
        start_ec = self.getEC()
        self._logger.detail("{} {}".format("Filling, Start EC:", start_ec))
        time.sleep(fill_time)

        # Check for level change first, else will never get to this logic till timeout
        end_ec = self.getEC()
        change = start_ec - end_ec
        if end_ec < start_ec:  # need to see at least a 5mm change
            self._logger.detail("{} {} {} {} {} {}".format(
                "Still Filling, change:", change, "Start", start_ec, "End",
                end_ec))
            return True
        else:
            self._logger.detail("{} {} {} {} {} {}".format(
                "Not Filling, no change:", change, "Start", start_ec, "End",
                end_ec))
            return False


# Check for timeout
        stop_time = time.time()
        if stop_time - start_time > self.res['timeout']:
            self._logger.detail("{}".format("Timeout"))
            return False
        else:
            return True

    def checkReservoir(self):
        '''Check condition of reservoir and fill if necessary'''
        self._logger.detail("{}".format("Check Reservoir"))
        status, ec = self.getStatus()
        self._logger.debug("{} {} {} {}".format("Status:", status, "EC", ec))

        # Is full, log state
        if status == Reservoir.FULL:
            self._logger.detail("{}".format("Status: Full"))
            self._logger.info("{} {} {} {}".format("EC:", ec, "Full level:",
                                                   self.res['full'], "Empty:",
                                                   self.res['empty']))
            return True
        else:
            # Needs filling
            self._logger.debug("{}".format("Status: Filling"))
            volume = self.fill()
            if volume > 0:
                # Filled, log volume
                self.logState(volume, 'Success')
                return True
            else:
                # Failure
                self._logger.debug("{}".format("Status: Failure"))
                level = 'Empty'
                if status == '2':
                    level = 'Ok'
                self._logger.error("{}".format("Failure to fill Reservoir"))
                self._logger.error("{} {} {} {}".format(
                    "EC:", ec, "Full level:", self.res['full'], "Empty:",
                    self.res['empty']))
                self.logState(volume, 'Failure')
                return False

    def logState(self, value, status_qualifier):

        if self._test:
            status_qualifier = 'Test'
        txt = {
            'Volume': value,
            'full_level': self.res['full'],
            'empty_level': self.res['empty'],
            'status': 'Full'
        }
        self._persist.save([
            'State_Change', '', 'Nutrient', 'Reservoir', 'Volume', value,
            'Liter', 'Solenoid', status_qualifier, ''
        ])
        self._logger.info(txt)
コード例 #9
0
ファイル: LogSensorsExtra.py プロジェクト: webbhm/NerdFarm
class LogSensorsExtra(object):
    def __init__(self, lvl=Logger.INFO):
        """Record optional sensor data
        Args:
            lvl: Logging level
        Returns:
            None
        Raises:
            None
        """
        self._logger = Logger("LogSensor-Extra",
                              lvl,
                              file="/home/pi/MVP/logs/obsv.log")
        self._activity_type = "Environment_Observation"
        self._test = False
        self._persist = Persistence(self._logger)

    def getOneWire(self, test=False):
        """Loop OneWire temperature sensors
            Assumes there are four
        Args:
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """
        self._logger.debug("In getOneWire")
        from OneWireTemp import OneWireTemp
        for sensor in OneWireTemp.one_temp:
            self.logOneWire(sensor, OneWireTemp.one_temp[sensor])

    def logOneWire(self, sensor, name, test=False):
        """Record OneWire temperature sensor
        Args:
            sensor: number of the sensor
            name: name of the sensor
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """
        self._logger.debug("In logOneWire")
        from OneWireTemp import OneWireTemp
        try:
            ow = OneWireTemp()
            temp = ow.getTempC(sensor)

            status_qualifier = 'Success'
            if self._test:
                status_qualifier = 'Test'
            rec = [
                self._activity_type, '', name, 'Air', 'Temperature',
                "{:10.1f}".format(temp), 'Centigrade',
                'DS18B20-' + str(sensor), status_qualifier, ''
            ]
            self._persist.save(rec)
            self._logger.info("{}, {}, {:10.1f}".format(
                name, status_qualifier, temp))
        except Exception as e:
            status_qualifier = 'Failure'
            if test:
                status_qualifier = 'Test'
            rec = [
                self._activity_type, '', name, 'Air', 'Temperature', '',
                'Centigrade', 'DS18B20-' + str(sensor), status_qualifier,
                str(e)
            ]
            self._persist.save(rec)
            self._logger.error("{}, {}, {}".format(name, status_qualifier, e))

    def getLux(self, test=False):
        """Record LUX sensor (TSL2561)
        Args:
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """
        from TSL2561 import TSL2561
        lx = TSL2561()
        self._logger.info("TSL2561 - LUX")

        try:
            lux = lx.getLux()
            status_qualifier = 'Success'
            if test:
                status_qualifier = 'Test'
            rec = [
                self._activity_type, '', 'Canopy', 'Light', 'LUX',
                "{:3.1f}".format(lux), 'lux', 'TSL2561', status_qualifier, ''
            ]
            self._persist.save(rec)
            self._logger.info("{}, {}, {:10.1f}".format(
                "LUX", status_qualifier, lux))
        except Exception as e:
            status_qualifier = 'Failure'
            if test:
                status_qualifier = 'Test'
            rec = [
                self._activity_type, '', 'Canopy', 'Light', 'LUX', '', 'lux',
                'TSL2561', status_qualifier,
                str(e)
            ]
            self._persist.save(rec)
            self._logger.error("{}, {}, {}".format("LUX", status_qualifier, e))

    def getEC(self, test=False):
        """Record EC sensor (EC - ADC reading)
        Args:
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """

        from EC import EC
        self._logger.info("EC")

        try:
            s = EC()
            ec = s.getEC()

            status_qualifier = 'Success'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("EC", status_qualifier, ec))
            rec = [
                self._activity_type, '', 'Reservoir', 'Nutrient', 'EC',
                "{:3.1f}".format(ec), 'EC', 'EC', status_qualifier, ''
            ]
            self._persist.save(rec)
            self._logger.info("{}, {}, {:10.1f}".format(
                "EC", status_qualifier, ec))
        except Exception as e:
            status_qualifier = 'Failure'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("EC", status_qualifier, ec))
            rec = [
                self._activity_type, '', 'Reservoir', 'Nutrient', 'EC', '',
                'EC', 'EC', status_qualifier,
                str(e)
            ]
            self._persist.save(rec)
            self._logger.error("{}, {}, {}".format("EC CCS811",
                                                   status_qualifier, e))

    def getCO2_NDIR(self, test=False):
        """Record CO2 sensor (NDIR)
        Args:
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """
        from NDIR import Sensor
        self._logger.info("CO2 - NDIR")
        try:
            sensor = Sensor()
            sensor.begin()
            co2 = sensor.getCO2()

            status_qualifier = 'Success'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("CO2 Canopy", status_qualifier,
                                                co2))
            rec = [
                self._activity_type, '', 'Canopy', 'Air', 'CO2',
                "{:3.1f}".format(co2), 'ppm', 'MH-Z16-NDIR', status_qualifier,
                ''
            ]
            self._persist.save(rec)
            self._logger.debug("{}, {}, {:10.1f}".format(
                "CO2", status_qualifier, co2))
        except Exception as e:
            status_qualifier = 'Failure'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("CO2 Canopy", status_qualifier,
                                                co2))
            rec = [
                self._activity_type, '', 'Canopy', 'Air', 'CO2', '', 'ppm',
                'MH-Z16-NDIR', status_qualifier,
                str(e)
            ]
            self._persist.save(rec)
            self._logger.error("{}, {}, {}".format("CO2 NDIR",
                                                   status_qualifier, e))

    def getCO2_CCS811(self, test=False):
        """Record CO2 sensor (CCS811)
        Args:
            test: flag for testing
        Returns:
            None
        Raises:
            None
        """
        from CCS811 import CCS811
        self._logger.info("CO2 CCS811")
        try:
            sensor = CCS811(SLAVE)
            co2 = sensor.get_co2()

            status_qualifier = 'Success'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("CO2 Canopy", status_qualifier,
                                                co2))
            rec = [
                self._activity_type, '', 'Canopy', 'Air', 'CO2',
                "{:3.1f}".format(co2), 'ppm', 'CCS811',
                str(e)
            ]
            self._persist.save(rec)
            self._logger.debug("{}, {}, {:10.1f}".format(
                "CCS811 - CO2", status_qualifier, co2))
        except Exception as e:
            status_qualifier = 'Failure'
            if test:
                status_qualifier = 'Test'
                print("{}, {}, {:10.1f}".format("CO2 Canopy", status_qualifier,
                                                co2))
            rec = [
                self._activity_type, '', 'Canopy', 'Air', 'CO2', '', 'ppm',
                'CCS811', status_qualifier,
                str(e)
            ]
            self._persist.save(rec)
            self._logger.error("{}, {}, {}".format("CO2 CCS811",
                                                   status_qualifier, e))

    def getSCD(self):
        """Record CO2 sensor (scd30)
            Generates co2, temperature and relative humidity
        Args:
            None
        Returns:
            None
        Raises:
            None
        """

        from scd30 import SCD30
        self._scd = SCD30(self._logger)
        self._logger.debug("In SCD30")
        try:
            co2, temp, rh = self._scd.get_data()

            status = 'Success'
            if self._test:
                status = 'Test'
            c_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'CO2',
                "{:10.1f}".format(co2), 'ppm', 'scd30', status, ''
            ]
            t_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'Temperature',
                "{:10.1f}".format(temp), 'Centigrade', 'scd30', status, ''
            ]
            h_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'Humidity',
                "{:10.1f}".format(rh), 'Percent', 'scd30', status, ''
            ]
            self._persist.save(c_rec)
            self._persist.save(t_rec)
            self._persist.save(h_rec)
            self._logger.info("{} {:6.1f}, {} {:3.1f}, {} {:3.1f}".format(
                "EnvObsv-CO2:", co2, "Temp", temp, "Humidity:", rh))
        except Exception as e:
            status = 'Failure'
            if self._test:
                status = 'Test'
            c_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'CO2', '', 'ppm',
                'scd30', status,
                str(e)
            ]
            t_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'Temperature', '',
                'Centigrde', 'scd30', status, ''
            ]
            h_rec = [
                'Environment_Observation', '', 'Top', 'Air', 'Humidity', '',
                'Percent', 'scd30', status, ''
            ]
            self._persist.save(c_rec)
            self._persist.save(t_rec)
            self._persist.save(h_rec)
            self._logger.debug("{} {}".format("EnvObsv-SCD30 Error:", e))

    def log(self):
        '''Log extra sensors
            Uncomment desired sensors
            Imports are in the function to avoid loading unnecessary code
        '''

        #self.getOneWire()

        self.getLux()

        self.getEC()

        self.getCO2_NDIR()

        #self.getCO2_CCS811()

        self.getSCD()