예제 #1
0
class DigitalSensor():
    def __init__(self, gpio, channel, invert=False):
        self.gpioname = gpio
        self.channel = toint(channel)
        if isinstance(invert, str):
            self.invert = str2bool(invert)
        else:
            self.invert = invert
        self.gpio = None
        self.setGPIOInstance()
        self.gpio.setFunction(self.channel, GPIO.IN)

    def __str__(self):
        return "DigitalSensor"

    def __family__(self):
        return "DigitalSensor"

    def setGPIOInstance(self):
        if not self.gpio:
            if self.gpioname != "GPIO":
                self.gpio = instance.deviceInstance(self.gpioname)
            else:
                self.gpio = GPIO()
            if self.gpio:
                self.gpio.setFunction(self.channel, GPIO.IN)

    #@request("GET", "value")
    @response("%d")
    def read(self):
        self.setGPIOInstance()
        value = self.gpio.digitalRead(self.channel)
        if self.invert:
            value = not value
        return int(value)
예제 #2
0
class GpioTest(unittest.TestCase):
    def setUp(self):
        self.gpio = NativeGPIO()

    def testGPIO(self):
        pins = []
        for header in self.gpio.MAPPING:
            pins.extend([
                pin['gpio'] for pin in header['map']
                if 'gpio' in pin and 'alt0' not in pin and 'overlay' not in pin
            ])
        for pin in pins:
            info('Testing pin {}'.format(pin))
            function = self.gpio.setFunctionString(pin, 'OUT')
            if function == 'UNKNOWN':
                info('Pin {} function UNKNOWN, skipping'.format(pin))
                continue
            self.assertEqual('OUT', function)
            value = self.gpio.digitalWrite(pin, 1)
            self.assertEqual(value, 1)
            value = self.gpio.digitalWrite(pin, 0)
            self.assertEqual(value, 0)

    def testPinStatus(self):
        pin_status = self.gpio.wildcard()
        info(pin_status)
        self.assertEqual(set(self.gpio.pins + self.gpio.overlay_pins),
                         set(pin_status.keys()))
        for key, value in pin_status.items():
            self.assertCountEqual(value.keys(), ('function', 'value'))
            if key in self.gpio.pins:
                self.assertGreaterEqual(value['value'], 0)
                self.assertLessEqual(value['value'], 1)
예제 #3
0
 def __init__(self):
     self.sensorMutex = RLock()
     self.systemMutex = RLock()
     self.continueMonitoring = False
     self.onDataChanged = None
     self.onSystemInfo = None
     self.currentBusInfo = self.previousBusInfo = None
     self.currentSensorsInfo = self.previousSensorsInfo = None
     self.currentSystemInfo = self.previousSystemInfo = None
     self.cpuLoadValues = {}
     self.disabledSensors = {}
     self.sensorsRefreshCount = 0
     self.retrievingSystemInfo = False
     self.disabledSensorTable = "disabled_sensors"
     self.systemInfoRefreshList = []
     checkAllBus()
     self.gpio = GPIO()
     manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [],
                               "system")
     manager.loadJsonDevices("rest")
     results = DbManager.Select(self.disabledSensorTable)
     if results:
         for row in results:
             self.disabledSensors[row[0]] = 1
     self.StartMonitoring()
예제 #4
0
 def getMessageBody(self, inviteCode):
     body = {'id': inviteCode}
     hardware = Hardware()
     if hardware.Serial and hardware.isRaspberryPi():
         body['type'] = 'rpi'
         body['hardware_id'] = hardware.Serial
     else:
         hardware_id = hardware.getMac()
         if hardware_id:
             body['type'] = 'mac'
             body['hardware_id'] = hardware_id
     try:
         system_data = []
         cayennemqtt.DataChannel.add(system_data,
                                     cayennemqtt.SYS_HARDWARE_MAKE,
                                     value=hardware.getManufacturer(),
                                     type='string',
                                     unit='utf8')
         cayennemqtt.DataChannel.add(system_data,
                                     cayennemqtt.SYS_HARDWARE_MODEL,
                                     value=hardware.getModel(),
                                     type='string',
                                     unit='utf8')
         system_info = SystemInfo()
         capacity_data = system_info.getMemoryInfo((cayennemqtt.CAPACITY, ))
         capacity_data += system_info.getDiskInfo((cayennemqtt.CAPACITY, ))
         for item in capacity_data:
             system_data.append(item)
         body['properties'] = {}
         body['properties']['pinmap'] = NativeGPIO().MAPPING
         if system_data:
             body['properties']['sysinfo'] = system_data
     except:
         exception('Error getting system info')
     return json.dumps(body)
예제 #5
0
파일: sensors.py 프로젝트: moauyed/sensors
 def __init__(self):
     """Initialize the bus and sensor info and start monitoring sensor states"""
     self.sensorMutex = RLock()
     self.realTimeMutex = RLock()
     self.exiting = Event()
     self.onDataChanged = None
     self.systemData = []
     self.currentSystemState = []
     self.currentRealTimeData = {}                                
     self.queuedRealTimeData = {}
     self.disabledSensors = {}
     self.disabledSensorTable = "disabled_sensors"
     checkAllBus()
     self.gpio = GPIO()
     self.downloadSpeed = DownloadSpeed(Config(APP_SETTINGS))
     self.downloadSpeed.getDownloadSpeed()
     manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [], "system")
     manager.loadJsonDevices("rest")
     results = DbManager.Select(self.disabledSensorTable)
     if results:
         for row in results:
             self.disabledSensors[row[0]] = 1
     self.realTimeMonitorRunning = False
     self.pluginManager = PluginManager(self.OnPluginChange)
     self.pluginManager.load_plugins()
     self.InitCallbacks()
     self.StartMonitoring()
예제 #6
0
 def setGPIOInstance(self):
     if not self.gpio:
         if self.gpioname != "GPIO":
             self.gpio = instance.deviceInstance(self.gpioname)
         else:
             self.gpio = GPIO()
         if self.gpio:
             self.gpio.setFunction(self.channel, GPIO.IN)
예제 #7
0
    def __init__(self, client):
        """Initialize the bus and sensor info and start monitoring sensor states"""
        self.cloudClient = client
        self.sensorMutex = RLock()
        self.realTimeMutex = RLock()
        self.exiting = Event()
        self.onDataChanged = None
        self.systemData = []
        self.currentSystemState = []
        self.currentRealTimeData = {}
        self.queuedRealTimeData = {}
        self.disabledSensors = {}
        self.disabledSensorTable = "disabled_sensors"
        checkAllBus()
        self.gpio = GPIO()
        # self.downloadSpeed = DownloadSpeed(Config(APP_SETTINGS))
        # self.downloadSpeed.getDownloadSpeed()
        manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [],
                                  "system")

        manager.loadJsonDevices("rest")

        if not DYNAMIC_DEVICES:
            warn("loadJsonDevices is None")
            for sensor in sensors.values():
                # info('--------{} {} {}'.format(sensor['name'], sensor['description'], sensor['device']))
                self.AddSensor(sensor['name'], sensor['description'],
                               sensor['device'], sensor['args'])

        #
        # info(DYNAMIC_DEVICES)
        self.config = Config(APP_SETTINGS)
        self.clientId = self.config.get('Agent', 'ClientID', None)
        self.mqtt_dis_prefix = self.config.get('Agent', 'MQTT_DIS_PREFIX',
                                               "homeassistant")
        self.serial = self.cloudClient.hardware.Serial

        for name, device in DYNAMIC_DEVICES.items():

            for type in device['type']:
                if type in ['DAC', 'ADC']:
                    continue
                topic, message = self.AddMQTTSensorDevice(name, type, device)

                if self.cloudClient:
                    info("{} {}".format(topic, message))
                    self.cloudClient.EnqueuePacket(message, topic)
                # info(mqttsensor)

        results = DbManager.Select(self.disabledSensorTable)
        if results:
            for row in results:
                self.disabledSensors[row[0]] = 1
        self.realTimeMonitorRunning = False
        self.pluginManager = PluginManager(self.OnPluginChange)
        self.pluginManager.load_plugins()
        self.InitCallbacks()
        self.StartMonitoring()
예제 #8
0
class GpioTest(unittest.TestCase):
    def setUp(self):
        self.gpio = NativeGPIO()

    def testGPIO(self):
        pins = []
        for header in self.gpio.MAPPING:
            pins.extend([
                pin['gpio'] for pin in header['map']
                if 'gpio' in pin and 'alt0' not in pin and 'overlay' not in pin
            ])
        for pin in pins:
            info('Testing pin {}'.format(pin))
            function = self.gpio.setFunctionString(pin, 'OUT')
            if function == 'UNKNOWN':
                info('Pin {} function UNKNOWN, skipping'.format(pin))
                continue
            self.assertEqual('OUT', function)
            value = self.gpio.digitalWrite(pin, 1)
            self.assertEqual(value, 1)
            value = self.gpio.digitalWrite(pin, 0)
            self.assertEqual(value, 0)

    def testPinStatus(self):
        pin_status = self.gpio.wildcard()
        info(pin_status)
        self.assertEqual(set(self.gpio.pins + self.gpio.overlay_pins),
                         set(pin_status.keys()))
        for key, value in pin_status.items():
            self.assertCountEqual(value.keys(), ('function', 'value'))
            if key in self.gpio.pins:
                self.assertGreaterEqual(value['value'], 0)
                self.assertLessEqual(value['value'], 1)

    def edgeCallback(self, data, value):
        info('edgeCallback data {}, value {}'.format(data, value))
        self.callback_data = data

    def testEdgeCallback(self):
        self.callback_data = 0
        pin = 27
        self.gpio.setFunctionString(pin, 'IN')
        self.gpio.setCallback(pin, self.edgeCallback, pin)
        for x in range(15):
            if self.callback_data != 0:
                break
            time.sleep(1)
        self.assertEqual(pin, self.callback_data)
예제 #9
0
 def __init__(self):
     """Initialize the bus and sensor info and start monitoring sensor states"""
     self.sensorMutex = RLock()
     self.exiting = Event()
     self.onDataChanged = None
     self.onSystemInfo = None
     self.systemData = []
     self.currentSystemState = []
     self.disabledSensors = {}
     self.disabledSensorTable = "disabled_sensors"
     checkAllBus()
     self.gpio = GPIO()
     manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [], "system")
     manager.loadJsonDevices("rest")
     results = DbManager.Select(self.disabledSensorTable)
     if results:
         for row in results:
             self.disabledSensors[row[0]] = 1
     self.StartMonitoring()
예제 #10
0
class SensorsClient():
    def __init__(self):
        self.sensorMutex = RLock()
        self.systemMutex = RLock()
        self.continueMonitoring = False
        self.onDataChanged = None
        self.onSystemInfo = None
        self.currentBusInfo = self.previousBusInfo = None
        self.currentSensorsInfo = self.previousSensorsInfo = None
        self.currentSystemInfo = self.previousSystemInfo = None
        self.cpuLoadValues = {}
        self.disabledSensors = {}
        self.sensorsRefreshCount = 0
        self.retrievingSystemInfo = False
        self.disabledSensorTable = "disabled_sensors"
        self.systemInfoRefreshList = []
        checkAllBus()
        self.gpio = GPIO()
        manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [],
                                  "system")
        manager.loadJsonDevices("rest")
        results = DbManager.Select(self.disabledSensorTable)
        if results:
            for row in results:
                self.disabledSensors[row[0]] = 1
        self.StartMonitoring()

    def SetDataChanged(self, onDataChanged=None, onSystemInfo=None):
        #one parameter only that contains data in a dictionary for changed items only
        self.onDataChanged = onDataChanged
        self.onSystemInfo = onSystemInfo

    def StartMonitoring(self):
        self.continueMonitoring = True
        #thread = Thread(target = self.Monitor)
        #thread.start()
        ThreadPool.Submit(self.Monitor)

    def StopMonitoring(self):
        self.continueMonitoring = False

    def Monitor(self):
        nextTime = datetime.now()
        nextTimeSystemInfo = datetime.now()
        debug('Monitoring sensors and os resources started')
        while self.continueMonitoring:
            try:
                if datetime.now() > nextTime:
                    self.raspberryValue = None
                    self.raspberryValue = {}
                    refreshTime = int(time())
                    if datetime.now() > nextTimeSystemInfo:
                        with self.systemMutex:
                            if not self.retrievingSystemInfo:
                                ThreadPool.Submit(
                                    self.MonitorSystemInformation())
                        nextTimeSystemInfo = datetime.now() + timedelta(
                            seconds=5)
                    self.MonitorSensors()
                    self.MonitorBus()
                    if self.onDataChanged != None:
                        self.onDataChanged(self.raspberryValue)
                    bResult = self.RemoveRefresh(refreshTime)
                    if bResult == True and self.onSystemInfo != None:
                        self.onSystemInfo()
                    self.sensorsRefreshCount += 1
                    nextTime = datetime.now() + timedelta(
                        seconds=REFRESH_FREQUENCY)
                sleep(REFRESH_FREQUENCY)
            except:
                exception("Monitoring sensors and os resources failed: " +
                          str())
        debug('Monitoring sensors and os resources Finished')

    def MonitorSensors(self):
        if self.continueMonitoring == False:
            return
        debug(
            str(time()) + ' Get sensors info ' + str(self.sensorsRefreshCount))
        self.SensorsInfo()
        debug(
            str(time()) + ' Got sensors info ' + str(self.sensorsRefreshCount))
        with self.sensorMutex:
            if self.SHA_Calc(self.currentSensorsInfo) != self.SHA_Calc(
                    self.previousSensorsInfo):
                #do merge
                mergedSensors = self.ChangedSensorsList()
                if self.previousSensorsInfo:
                    del self.previousSensorsInfo
                    self.previousSensorsInfo = None
                if mergedSensors == None:
                    self.previousSensorsInfo = self.currentSensorsInfo
                    return
                self.raspberryValue['SensorsInfo'] = mergedSensors
                self.previousSensorsInfo = self.currentSensorsInfo
        debug(
            str(time()) + ' Merge sensors info ' +
            str(self.sensorsRefreshCount))

    def ChangedSensorsList(self):
        if self.continueMonitoring == False:
            return None
        if self.previousSensorsInfo == None:
            return None
        if self.currentSensorsInfo == None:
            return None
        changedSensors = []
        previousSensorsDictionary = dict(
            (i['sensor'], i) for i in self.previousSensorsInfo)
        for item in self.currentSensorsInfo:
            oldItem = None
            if item['sensor'] in previousSensorsDictionary:
                oldItem = previousSensorsDictionary[item['sensor']]
                if self.SHA_Calc(item) != self.SHA_Calc(oldItem):
                    changedSensors.append(item)
            else:
                changedSensors.append(item)
        return changedSensors

    def MonitorBus(self):
        if self.continueMonitoring == False:
            return
        debug(str(time()) + ' Get bus info ' + str(self.sensorsRefreshCount))
        self.BusInfo()
        debug(str(time()) + ' Got bus info ' + str(self.sensorsRefreshCount))
        if self.SHA_Calc(self.currentBusInfo) != self.SHA_Calc(
                self.previousBusInfo):
            self.raspberryValue['BusInfo'] = self.currentBusInfo
            if self.previousBusInfo:
                del self.previousBusInfo
                self.previousBusInfo = None
            self.previousBusInfo = self.currentBusInfo

    def MonitorSystemInformation(self):
        if self.continueMonitoring == False:
            return
        debug(
            str(time()) + ' Get system info ' + str(self.sensorsRefreshCount))
        self.SystemInformation()
        debug(
            str(time()) + ' Got system info ' + str(self.sensorsRefreshCount))
        firstSHA = self.SHA_Calc(self.currentSystemInfo)
        secondSHA = self.SHA_Calc(self.previousSystemInfo)
        if firstSHA != secondSHA:
            if self.previousSystemInfo:
                del self.previousSystemInfo
                self.previousSystemInfo = None
            self.previousSystemInfo = self.currentSystemInfo
            self.raspberryValue['SystemInfo'] = self.currentSystemInfo

    def SystemInformation(self):
        with self.systemMutex:
            self.retrievingSystemInfo = True
        try:
            jsonInfo = "{}"
            debug('SystemInfo Spawning child process from pid:' +
                  str(getpid()))
            (jsonInfo, retCode) = services.ServiceManager.ExecuteCommand(
                "python3 -m myDevices.os.getsysteminfo")
            if int(retCode) == 0:
                newSystemInfo = loads(jsonInfo)
                if self.currentSystemInfo:
                    del self.currentSystemInfo
                    self.currentSystemInfo = None
                self.currentSystemInfo = newSystemInfo
                del jsonInfo
                from myDevices.os.cpu import GetCpuLoad
                cpuLoad = GetCpuLoad()
                newCpuLoadValues = cpuLoad.getcpuload()
                if newCpuLoadValues['cpu'] != 0.0:
                    self.cpuLoadValues = newCpuLoadValues
                self.currentSystemInfo['CpuLoad'] = self.cpuLoadValues
        except Exception as ex:
            exception('SystemInformation failed: ' + str(ex))
        with self.systemMutex:
            self.retrievingSystemInfo = False
        return self.currentSystemInfo

    def SHA_Calc(self, object):
        if object == None:
            return ''
        try:
            strVal = dumps(object)
        except:
            exception('SHA_Calc failed for:' + str(object))
            return ''
        return self.SHA_Calc_str(strVal)

    def SHA_Calc_str(self, stringVal):
        m = sha1()
        m.update(stringVal.encode('utf8'))
        sDigest = str(m.hexdigest())
        return sDigest

    def AppendToDeviceList(self, device_list, source, device_type):
        device = source.copy()
        del device['origin']
        device['name'] = parse.unquote(device['name'])
        device['type'] = device_type
        if len(source['type']) > 1:
            device['hash'] = self.SHA_Calc_str(device['name'] + device['type'])
        else:
            device['hash'] = self.SHA_Calc_str(device['name'] +
                                               device['device'])
        if device['hash'] in self.disabledSensors:
            device['enabled'] = 0
        else:
            device['enabled'] = 1
        device_list.append(device)

    def GetDevices(self):
        device_list = manager.getDeviceList()
        devices = []
        for dev in device_list:
            try:
                if len(dev['type']) == 0:
                    self.AppendToDeviceList(devices, dev, '')
                else:
                    for device_type in dev['type']:
                        self.AppendToDeviceList(devices, dev, device_type)
            except:
                exception("Failed to get device: {}".format(dev))
        return devices

    def CallDeviceFunction(self, func, *args):
        result = func(*args)
        if result != None:
            if hasattr(func, "contentType"):
                if func.contentType != M_JSON:
                    value_type = type(result)
                    response = value_type(func.format % result)
                else:
                    response = result
            else:
                response = result
        return response

    def BusInfo(self):
        json = {}
        for (bus, value) in BUSLIST.items():
            json[bus] = int(value["enabled"])
        gpios = {}
        for gpio in range(GPIO.GPIO_COUNT):
            gpios[gpio] = {}
            gpios[gpio]['function'] = self.gpio.getFunctionString(gpio)
            gpios[gpio]['value'] = int(self.gpio.input(gpio))
        json['GPIO'] = gpios
        json['GpioMap'] = MAPPING
        self.currentBusInfo = json
        return self.currentBusInfo

    def SensorsInfo(self):
        with self.sensorMutex:
            devices = self.GetDevices()
            debug(
                str(time()) + ' Got devices info ' +
                str(self.sensorsRefreshCount))
            if devices is None:
                return {}
            for value in devices:
                sensor = instance.deviceInstance(value['name'])
                if 'enabled' not in value or value['enabled'] == 1:
                    sleep(SENSOR_INFO_SLEEP)
                    try:
                        if value['type'] == 'Temperature':
                            value['Celsius'] = self.CallDeviceFunction(
                                sensor.getCelsius)
                            value['Fahrenheit'] = self.CallDeviceFunction(
                                sensor.getFahrenheit)
                            value['Kelvin'] = self.CallDeviceFunction(
                                sensor.getKelvin)
                        if value['type'] == 'Pressure':
                            value['Pascal'] = self.CallDeviceFunction(
                                sensor.getPascal)
                        if value['type'] == 'Luminosity':
                            value['Lux'] = self.CallDeviceFunction(
                                sensor.getLux)
                        if value['type'] == 'Distance':
                            value['Centimeter'] = self.CallDeviceFunction(
                                sensor.getCentimeter)
                            value['Inch'] = self.CallDeviceFunction(
                                sensor.getInch)
                        if value['type'] in ('ADC', 'DAC', 'PWM'):
                            value['channelCount'] = self.CallDeviceFunction(
                                sensor.analogCount)
                            value['maxInteger'] = self.CallDeviceFunction(
                                sensor.analogMaximum)
                            value['resolution'] = self.CallDeviceFunction(
                                sensor.analogResolution)
                            value['allInteger'] = self.CallDeviceFunction(
                                sensor.analogReadAll)
                            value['allVolt'] = self.CallDeviceFunction(
                                sensor.analogReadAllVolt)
                            value['allFloat'] = self.CallDeviceFunction(
                                sensor.analogReadAllFloat)
                            if value['type'] in ('DAC'):
                                value['vref'] = self.CallDeviceFunction(
                                    sensor.analogReference)
                        if value['type'] == 'PWM':
                            value['channelCount'] = self.CallDeviceFunction(
                                sensor.pwmCount)
                            value['maxInteger'] = self.CallDeviceFunction(
                                sensor.pwmMaximum)
                            value['resolution'] = self.CallDeviceFunction(
                                sensor.pwmResolution)
                            value['all'] = self.CallDeviceFunction(
                                sensor.pwmWildcard)
                        if value['type'] == 'Humidity':
                            value['float'] = self.CallDeviceFunction(
                                sensor.getHumidity)
                            value['percent'] = self.CallDeviceFunction(
                                sensor.getHumidityPercent)
                        if value['type'] == 'PiFaceDigital':
                            value['all'] = self.CallDeviceFunction(
                                sensor.readAll)
                        if value['type'] in ('DigitalSensor',
                                             'DigitalActuator'):
                            value['value'] = self.CallDeviceFunction(
                                sensor.read)
                        if value['type'] == 'GPIOPort':
                            value['channelCount'] = self.CallDeviceFunction(
                                sensor.digitalCount)
                            value['all'] = self.CallDeviceFunction(
                                sensor.wildcard)
                        if value['type'] == 'AnalogSensor':
                            value['integer'] = self.CallDeviceFunction(
                                sensor.read)
                            value['float'] = self.CallDeviceFunction(
                                sensor.readFloat)
                            value['volt'] = self.CallDeviceFunction(
                                sensor.readVolt)
                        if value['type'] == 'ServoMotor':
                            value['angle'] = self.CallDeviceFunction(
                                sensor.readAngle)
                        if value['type'] == 'AnalogActuator':
                            value['float'] = self.CallDeviceFunction(
                                sensor.readFloat)
                    except:
                        exception("Sensor values failed: " + value['type'] +
                                  " " + value['name'])
                try:
                    if 'hash' in value:
                        value['sensor'] = value['hash']
                        del value['hash']
                except KeyError:
                    pass
            if self.currentSensorsInfo:
                del self.currentSensorsInfo
                self.currentSensorsInfo = None
            self.currentSensorsInfo = devices
            devices = None
        if self.sensorsRefreshCount == 0:
            info('System sensors info at start ' +
                 str(self.currentSensorsInfo))
        debug(('New sensors info retrieved: {}').format(
            self.sensorsRefreshCount))
        logJson('Sensors Info updated: ' + str(self.currentSensorsInfo))
        return self.currentSensorsInfo

    def AddSensor(self, name, description, device, args):
        info('AddSensor: {}, {}, {}, {}'.format(name, description, device,
                                                args))
        bVal = False
        try:
            sensorAdd = {}
            if name:
                sensorAdd['name'] = req.pathname2url(name)
            if device:
                sensorAdd['device'] = device
            if args:
                sensorAdd['args'] = args
            if description:
                sensorAdd['description'] = description
            with self.sensorMutex:
                retValue = manager.addDeviceJSON(sensorAdd)
            info('Add device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
                self.AddRefresh()
        except:
            bVal = False
        return bVal

    def EditSensor(self, name, description, device, args):
        info('EditSensor: {}, {}, {}, {}'.format(name, description, device,
                                                 args))
        bVal = False
        try:
            sensorEdit = {}
            name = req.pathname2url(name)
            sensorEdit['name'] = name
            sensorEdit['device'] = device
            sensorEdit['description'] = description
            sensorEdit['args'] = args
            with self.sensorMutex:
                retValue = manager.updateDevice(name, sensorEdit)
            info('Edit device returned: {}'.format(retValue))
            try:
                hashKey = self.SHA_Calc_str(name + device)
                with self.sensorMutex:
                    if self.currentSensorsInfo:
                        currentSensorsDictionary = dict(
                            (i['sensor'], i) for i in self.currentSensorsInfo)
                        sensorData = currentSensorsDictionary[hashKey]
                        sensor = sensorData[hashKey]
                        raspberryValue = {}
                        sensor['args'] = args
                        sensor['description'] = description
                        raspberryValue['SensorsInfo'] = []
                        raspberryValue['SensorsInfo'].append(sensor)
                        if self.onDataChanged != None:
                            self.onDataChanged(raspberryValue)
            except:
                pass
            if retValue[0] == 200:
                bVal = True
                self.AddRefresh()
        except:
            exception("Edit sensor failed")
            bVal = False
        return bVal

    def DeleteSensor(self, name):
        bVal = False
        try:
            sensorRemove = req.pathname2url(name)
            with self.sensorMutex:
                retValue = manager.removeDevice(sensorRemove)
            info('Remove device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
                self.AddRefresh()
        except:
            exception("Remove sensor failed")
            bVal = False
        return bVal

    def RemoveSensor(self, name):
        debug('')
        return self.DeleteSensor(name)

    def EnableSensor(self, sensor, enable):
        #sensor is the hash composed from name and device class/type
        info('Enable sensor: ' + str(sensor) + ' ' + str(enable))
        try:
            if sensor is None:
                return False
            if enable is None:
                return False
            with self.sensorMutex:
                if enable == 0:
                    #add item to the list
                    if sensor not in self.disabledSensors:
                        rowId = DbManager.Insert(self.disabledSensorTable,
                                                 sensor)
                        self.disabledSensors[sensor] = 1
                else:
                    #remove item from the list
                    if sensor in self.disabledSensors:
                        DbManager.Delete(self.disabledSensorTable, sensor)
                        del self.disabledSensors[sensor]
                    #save list
        except Exception as ex:
            error('EnableSensor Failed with exception: ' + str(ex))
            return False
        self.AddRefresh()
        return True

    def AddRefresh(self):
        self.systemInfoRefreshList.append(int(time()))

    def RemoveRefresh(self, newRefresh):
        bReturn = False
        for i in self.systemInfoRefreshList:
            if i < newRefresh:
                self.systemInfoRefreshList.remove(i)
                bReturn = True
        return bReturn

    def GpioCommand(self, commandType, method, channel, value):
        debug('')
        info('GpioCommand ' + commandType + ' method ' + method +
             ' Channel: ' + str(channel) + ' Value: ' + str(value))
        if commandType == 'function':
            if method == 'POST':
                debug('setFunction:' + str(channel) + ' ' + str(value))
                return str(self.gpio.setFunctionString(channel, value))
            if method == 'GET':
                debug('getFunction:' + str(channel) + ' ' + str(value))
                return str(self.gpio.getFunctionString(channel))
        if commandType == 'value':
            if method == 'POST':
                debug('digitalWrite:' + str(channel) + ' ' + str(value))
                retVal = str(self.gpio.digitalWrite(channel, value))
                return retVal
            if method == 'GET':
                debug('digitalRead:' + str(channel))
                return str(self.gpio.digitalRead(channel))
        if commandType == 'integer':
            if method == 'POST':
                debug('portWrite:' + str(value))
                return str(self.gpio.portWrite(value))
            if method == 'GET':
                debug('portRead:')
                return str(self.gpio.portRead())
        debug.log('GpioCommand not set')
        return 'failure'

    def SensorCommand(self, commandType, sensorName, sensorType, driverClass,
                      method, channel, value):
        retVal = False
        info(
            'SensorCommand: {} SensorName {} SensorType {} DriverClass {} Method {} Channel {} Value {}'
            .format(commandType, sensorName, sensorType, driverClass, method,
                    channel, value))
        try:
            self.AddRefresh()
            debug('')
            actuators = ('GPIOPort', 'ServoMotor', 'AnalogActuator',
                         'LoadSensor', 'PiFaceDigital', 'DistanceSensor',
                         'Thermistor', 'Photoresistor', 'LightDimmer',
                         'LightSwitch', 'DigitalSensor', 'DigitalActuator',
                         'MotorSwitch', 'RelaySwitch', 'ValveSwitch',
                         'MotionSensor')
            gpioExtensions = ('GPIOPort', 'PiFaceDigital')
            if driverClass is None:
                hashKey = self.SHA_Calc_str(sensorName + sensorType)
            else:
                hashKey = self.SHA_Calc_str(sensorName + driverClass)
            with self.sensorMutex:
                if hashKey in self.disabledSensors:
                    return retVal
                sensor = instance.deviceInstance(sensorName)
                if not sensor:
                    info('Sensor not found')
                    return retVal
                if (sensorType in actuators) or (driverClass in actuators):
                    if sensorType in gpioExtensions or driverClass in gpioExtensions:
                        if commandType == 'integer' or commandType == 'value':
                            retVal = str(
                                self.CallDeviceFunction(
                                    sensor.write, int(channel), int(value)))
                            return retVal
                    else:
                        if commandType == 'integer':
                            retVal = str(
                                self.CallDeviceFunction(
                                    sensor.write, int(value)))
                            return retVal
                    if commandType == 'function':
                        retVal = str(
                            self.CallDeviceFunction(sensor.setFunctionString,
                                                    channel, value))
                        return retVal
                    if commandType == 'angle':
                        retVal = self.CallDeviceFunction(
                            sensor.writeAngle, value)
                        return retVal
                    if commandType == 'float':
                        retVal = self.CallDeviceFunction(
                            sensor.writeFloat, float(value))
                        return retVal
                if commandType == 'integer':
                    retVal = float(
                        self.CallDeviceFunction(sensor.write, int(channel),
                                                int(value)))
                    return retVal
                if commandType == 'float':
                    retVal = float(
                        self.CallDeviceFunction(sensor.writeFloat,
                                                int(channel), float(value)))
                    return retVal
                if commandType == 'volt':
                    retVal = float(
                        self.CallDeviceFunction(sensor.writeVolt, int(channel),
                                                float(value)))
                    return retVal
                if commandType == 'angle':
                    retVal = float(
                        self.CallDeviceFunction(sensor.writeAngle,
                                                int(channel), float(value)))
                    return retVal
                warn('Command not implemented: ' + commandType)
                return retVal
        except Exception as ex:
            exception('SensorCommand failed with: ' + str(ex))
            pass
        finally:
            #looks like this breaks actuators refresh by updating and not sending data changed
            #then refresh never comes for the specific sensor
            #ThreadPool.SubmitParam(self.Monitor, hashKey)
            return retVal
예제 #11
0
 def setUp(self):
     self.gpio = NativeGPIO()
예제 #12
0
파일: sensors.py 프로젝트: moauyed/sensors
class SensorsClient():
    """Class for interfacing with sensors and actuators"""

    def __init__(self):
        """Initialize the bus and sensor info and start monitoring sensor states"""
        self.sensorMutex = RLock()
        self.realTimeMutex = RLock()
        self.exiting = Event()
        self.onDataChanged = None
        self.systemData = []
        self.currentSystemState = []
        self.currentRealTimeData = {}                                
        self.queuedRealTimeData = {}
        self.disabledSensors = {}
        self.disabledSensorTable = "disabled_sensors"
        checkAllBus()
        self.gpio = GPIO()
        self.downloadSpeed = DownloadSpeed(Config(APP_SETTINGS))
        self.downloadSpeed.getDownloadSpeed()
        manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [], "system")
        manager.loadJsonDevices("rest")
        results = DbManager.Select(self.disabledSensorTable)
        if results:
            for row in results:
                self.disabledSensors[row[0]] = 1
        self.realTimeMonitorRunning = False
        self.pluginManager = PluginManager(self.OnPluginChange)
        self.pluginManager.load_plugins()
        self.InitCallbacks()
        self.StartMonitoring()

    def SetDataChanged(self, onDataChanged=None):
        """Set callback to call when data has changed
        
        Args:
            onDataChanged: Function to call when sensor data changes
        """
        self.onDataChanged = onDataChanged

    def QueueRealTimeData(self, name, data):
        """Add real-time data to queue to be sent on thread

        Args:
            name: The name to use for the data
            data: The data to send
        """
        with self.realTimeMutex:
            if name not in self.currentRealTimeData:
                self.currentRealTimeData[name] = data
            else:
                self.queuedRealTimeData[name] = data

    def OnSensorChange(self, device, value):
        """Callback that is called when digital sensor data has changed

        Args:
            device: The device that has changed data
            value: The new data value
        """
        debug('OnSensorChange: {}, {}'.format(device, value))
        with self.realTimeMutex:
            data = {'name': device['description'], 'value': value, 'type': 'digital_sensor', 'unit': 'd'}
            if 'args' in device:
                data['args'] = device['args']
            self.QueueRealTimeData(device['name'], data)

    def OnPluginChange(self, data):
        """Callback that is called when digital sensor data has changed

        Args:
            data: The new data value
        """
        debug('OnPluginChange: {}'.format(data))
        self.QueueRealTimeData(data['id'], data)
        with self.realTimeMutex:
            if not self.realTimeMonitorRunning:
                ThreadPool.Submit(self.RealTimeMonitor)

    def OnGpioStateChange(self, channel, value):
        """Send updated pin state when it has changed

        Args:
            channel: The pin number
            value: The new value for the pin
        """
        debug('OnGpioStateChange: channel {}, value {}'.format(channel, value))
        data = []
        cayennemqtt.DataChannel.add_unique(data, cayennemqtt.SYS_GPIO, channel, cayennemqtt.VALUE, value)
        if not self.realTimeMonitorRunning:
            self.onDataChanged(data)
        else:
            self.QueueRealTimeData(data[0]['channel'], data[0])

    def InitCallbacks(self):
        """Set callback function for any digital devices that support them"""
        devices = manager.getDeviceList()
        for device in devices:
            sensor = instance.deviceInstance(device['name'])
            if 'DigitalSensor' in device['type'] and hasattr(sensor, 'setCallback'):
                debug('Set callback for {}'.format(sensor))
                sensor.setCallback(self.OnSensorChange, device)
                if not self.realTimeMonitorRunning:
                    ThreadPool.Submit(self.RealTimeMonitor)

    def RemoveCallbacks(self):
        """Remove callback function for all digital devices"""
        devices = manager.getDeviceList()
        for device in devices:
            sensor = instance.deviceInstance(device['name'])
            if 'DigitalSensor' in device['type'] and hasattr(sensor, 'removeCallback'):
                sensor.removeCallback()

    def StartMonitoring(self):
        """Start thread monitoring sensor data"""
        ThreadPool.Submit(self.Monitor)

    def StopMonitoring(self):
        """Stop thread monitoring sensor data"""
        self.RemoveCallbacks()
        self.exiting.set()

    def Monitor(self):
        """Monitor bus/sensor states and system info and report changed data via callbacks"""
        debug('Monitoring sensors and os resources started')
        sendAllDataCount = 0
        nextTime = datetime.now()
        while not self.exiting.is_set():
            try:
                difference = nextTime - datetime.now()
                delay = min(REFRESH_FREQUENCY, difference.total_seconds())
                delay = max(0, delay)
                if not self.exiting.wait(delay):
                    nextTime = datetime.now() + timedelta(seconds=REFRESH_FREQUENCY)
                    self.currentSystemState = []
                    self.MonitorSystemInformation()
                    self.MonitorSensors()
                    self.MonitorPlugins()
                    self.MonitorBus()
                    if self.currentSystemState != self.systemData:
                        data = self.currentSystemState
                        if self.systemData and not sendAllDataCount == 0:
                            data = [x for x in self.currentSystemState if x not in self.systemData]
                        if self.onDataChanged and data:
                            self.onDataChanged(data)
                    sendAllDataCount += 1
                    if sendAllDataCount >= 4:
                        sendAllDataCount = 0
                    self.systemData = self.currentSystemState
            except:
                exception('Monitoring sensors and os resources failed')
        debug('Monitoring sensors and os resources finished')

    def RealTimeMonitor(self):
        """Monitor real-time state changes and report changed data via callbacks"""
        self.realTimeMonitorRunning = True
        info('Monitoring real-time state changes')
        nextTime = datetime.now()
        while not self.exiting.is_set():
            try:
                if not self.exiting.wait(0.5):
                    if datetime.now() > nextTime:
                        nextTime = datetime.now() + timedelta(seconds=REAL_TIME_FREQUENCY)
                        self.SendRealTimeData()
            except:
                exception('Monitoring real-time changes failed')
        debug('Monitoring real-time changes finished')
        self.realTimeMonitorRunning = False

    def SendRealTimeData(self):
        """Send real-time data via callback"""
        data = []
        with self.realTimeMutex:
            if self.currentRealTimeData:
                for name, item in self.currentRealTimeData.items():
                    if cayennemqtt.SYS_GPIO in name:
                        data.append(item)
                    else: 
                        cayennemqtt.DataChannel.add_unique(data, cayennemqtt.DEV_SENSOR, name, value=item['value'], name=item['name'], type=item['type'], unit=item['unit'])
                        try:
                            cayennemqtt.DataChannel.add_unique(data, cayennemqtt.SYS_GPIO, item['args']['channel'], cayennemqtt.VALUE, item['value'])
                        except:
                            pass
                        if name in self.queuedRealTimeData and self.queuedRealTimeData[name]['value'] == item['value']:
                            del self.queuedRealTimeData[name]
                self.currentRealTimeData = self.queuedRealTimeData
                self.queuedRealTimeData = {}
        if data:
            self.onDataChanged(data)

    def MonitorSensors(self):
        """Check sensor states for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.SensorsInfo()

    def MonitorPlugins(self):
        """Check plugin states for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.pluginManager.get_plugin_readings()

    def MonitorBus(self):
        """Check bus states for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.BusInfo()

    def MonitorSystemInformation(self):
        """Check system info for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.SystemInformation()

    def SystemInformation(self):
        """Return dict containing current system info, including CPU, RAM, storage and network info"""
        newSystemInfo = []
        try:
            systemInfo = SystemInfo()
            newSystemInfo = systemInfo.getSystemInformation()
            download_speed = self.downloadSpeed.getDownloadSpeed()
            if download_speed:
                cayennemqtt.DataChannel.add(newSystemInfo, cayennemqtt.SYS_NET, suffix=cayennemqtt.SPEEDTEST, value=download_speed, type='bw', unit='mbps')
        except Exception:
            exception('SystemInformation failed')
        return newSystemInfo

    def CallDeviceFunction(self, func, *args):
        """Call a function for a sensor/actuator device and format the result value type

        Args:
            func: Function to call
            args: Parameters to pass to the function

        Returns:
            True for success, False otherwise.
        """
        result = func(*args)
        if result != None:
            if hasattr(func, "contentType"):
                if func.contentType != M_JSON:
                    value_type = type(result)
                    response = value_type(func.format % result)
                else:
                    response = result
            else:
                response = result
        return response

    def BusInfo(self):
        """Return a dict with current bus info"""
        bus_info = []
        gpio_state = self.gpio.wildcard()
        for key, value in gpio_state.items():
            cayennemqtt.DataChannel.add(bus_info, cayennemqtt.SYS_GPIO, key, cayennemqtt.VALUE, value['value'])
            cayennemqtt.DataChannel.add(bus_info, cayennemqtt.SYS_GPIO, key, cayennemqtt.FUNCTION, value['function'])
        return bus_info

    def SensorsInfo(self):
        """Return a list with current sensor states for all enabled sensors"""
        manager.deviceDetector()
        devices = manager.getDeviceList()
        sensors_info = []
        if devices is None:
            return sensors_info
        for device in devices:
            sensor = instance.deviceInstance(device['name'])
            if 'enabled' not in device or device['enabled'] == 1:
                sensor_types = {'Temperature': {'function': 'getCelsius', 'data_args': {'type': 'temp', 'unit': 'c'}},
                                'Humidity': {'function': 'getHumidityPercent', 'data_args': {'type': 'rel_hum', 'unit': 'p'}},
                                'Pressure': {'function': 'getPascal', 'data_args': {'type': 'bp', 'unit': 'pa'}},
                                'Luminosity': {'function': 'getLux', 'data_args': {'type': 'lum', 'unit': 'lux'}},
                                'Distance': {'function': 'getCentimeter', 'data_args': {'type': 'prox', 'unit': 'cm'}},
                                'ServoMotor': {'function': 'readAngle', 'data_args': {'type': 'analog_actuator'}},
                                'DigitalSensor': {'function': 'read', 'data_args': {'type': 'digital_sensor', 'unit': 'd'}},
                                'DigitalActuator': {'function': 'read', 'data_args': {'type': 'digital_actuator', 'unit': 'd'}},
                                'AnalogSensor': {'function': 'readFloat', 'data_args': {'type': 'analog_sensor'}},
                                'AnalogActuator': {'function': 'readFloat', 'data_args': {'type': 'analog_actuator'}}}
                # extension_types = {'ADC': {'function': 'analogReadAllFloat'},
                #                     'DAC': {'function': 'analogReadAllFloat'},
                #                     'PWM': {'function': 'pwmWildcard'},
                #                     'GPIOPort': {'function': 'wildcard'}}
                for device_type in device['type']:
                    try:
                        display_name = device['description']
                    except:
                        display_name = None
                    if device_type in sensor_types:
                        try:
                            sensor_type = sensor_types[device_type]
                            func = getattr(sensor, sensor_type['function'])
                            if len(device['type']) > 1:
                                channel = '{}:{}'.format(device['name'], device_type.lower())
                            else:
                                channel = device['name']
                            value = self.CallDeviceFunction(func)
                            cayennemqtt.DataChannel.add(sensors_info, cayennemqtt.DEV_SENSOR, channel, value=value, name=display_name, **sensor_type['data_args'])
                            if 'DigitalActuator' == device_type and value in (0, 1):
                                manager.updateDeviceState(device['name'], value)
                        except:
                            exception('Failed to get sensor data: {} {}'.format(device_type, device['name']))
                    # else:
                    #     try:
                    #         extension_type = extension_types[device_type]
                    #         func = getattr(sensor, extension_type['function'])
                    #         values = self.CallDeviceFunction(func)
                    #         for pin, value in values.items():
                    #             cayennemqtt.DataChannel.add(sensors_info, cayennemqtt.DEV_SENSOR, device['name'] + ':' + str(pin), cayennemqtt.VALUE, value, name=display_name)
                    #     except:
                    #         exception('Failed to get extension data: {} {}'.format(device_type, device['name']))
        info('Sensors info: {}'.format(sensors_info))
        return sensors_info

    def AddSensor(self, name, description, device, args):
        """Add a new sensor/actuator
   
        Args:
            name: Name of sensor to add
            description: Sensor description
            device: Sensor device class
            args: Sensor specific args

        Returns:
            True for success, False otherwise.
        """
        info('AddSensor: {}, {}, {}, {}'.format(name, description, device, args))
        bVal = False
        try:
            sensorAdd = {}
            if name:
                sensorAdd['name'] = name
            if device:
                sensorAdd['device'] = device
            if args:
                sensorAdd['args'] = args
            if description:
                sensorAdd['description'] = description
            with self.sensorMutex:
                retValue = manager.addDeviceJSON(sensorAdd)
                self.InitCallbacks()
            info('Add device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except Exception:
            exception('Error adding sensor')
            bVal = False
        return bVal

    def EditSensor(self, name, description, device, args):
        """Edit an existing sensor/actuator
  
        Args:
            name: Name of sensor to edit
            description: New sensor description
            device: New sensor device class
            args: New sensor specific args

        Returns:
            True for success, False otherwise.
        """
        info('EditSensor: {}, {}, {}, {}'.format(name, description, device, args))
        bVal = False
        try:
            sensorEdit = {}
            name = name
            sensorEdit['name'] = name
            sensorEdit['device'] = device
            sensorEdit['description'] = description
            sensorEdit['args'] = args
            with self.sensorMutex:
                retValue = manager.updateDevice(name, sensorEdit)
                self.InitCallbacks()
            info('Edit device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except:
            exception("Edit sensor failed")
            bVal = False
        return bVal

    def RemoveSensor(self, name):
        """Remove an existing sensor/actuator

        Args:
            name: Name of sensor to remove

        Returns:
            True for success, False otherwise.
        """
        bVal = False
        try:
            if self.pluginManager.is_plugin(name):
                return self.pluginManager.disable(name)
            sensorRemove = name
            try:
                sensor = instance.deviceInstance(sensorRemove)
                if hasattr(sensor, 'removeCallback'):
                    sensor.removeCallback()
            except: 
                pass
            with self.sensorMutex:
                retValue = manager.removeDevice(sensorRemove)
            info('Remove device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except:
            exception("Remove sensor failed")
            bVal = False
        return bVal

    def EnableSensor(self, sensor, enable):
        """Enable a sensor/actuator

        Args:
            sensor: Hash composed from name and device class/type
            enable: 1 to enable, 0 to disable

        Returns:
            True for success, False otherwise.
        """
        info('Enable sensor: ' + str(sensor) + ' ' + str(enable))
        try:
            if sensor is None:
                return False
            if enable is None:
                return False
            with self.sensorMutex:
                if enable == 0:
                    #add item to the list
                    if sensor not in self.disabledSensors:
                        DbManager.Insert(self.disabledSensorTable, sensor)
                        self.disabledSensors[sensor] = 1
                else:
                    #remove item from the list
                    if sensor in self.disabledSensors:
                        DbManager.Delete(self.disabledSensorTable, sensor)
                        del self.disabledSensors[sensor]
                    #save list
        except Exception as ex:
            error('EnableSensor Failed with exception: '  + str(ex))
            return False
        return True

    def GpioCommand(self, command, channel, value):
        """Execute onboard GPIO command

        Args:
            command: Type of command to execute
            channel: GPIO pin
            value: Value to use for writing data

        Returns:
            String containing command specific return value on success, or 'failure' on failure
        """
        info('GpioCommand {}, channel {}, value {}'.format(command, channel, value))
        result = 'failure'
        if command == 'function':
            old_state = self.gpio.digitalRead(channel)
            if value.lower() in ('in', 'input'):
                result = str(self.gpio.setFunctionString(channel, 'in'))
            elif value.lower() in ('out', 'output'):
                result = str(self.gpio.setFunctionString(channel, 'out'))
            new_state = self.gpio.digitalRead(channel)
            if new_state != old_state:
                self.OnGpioStateChange(channel, new_state)
        elif command in ('value', ''):
            return self.gpio.digitalWrite(channel, int(value))
        debug('GPIO command failed')
        return result

    def SensorCommand(self, command, sensorId, channel, value):
        """Execute sensor/actuator command

        Args:
            command: Type of command to execute
            sensorId: Sensor id
            channel: Pin/channel on device, None if there is no channel
            value: Value to use for setting the sensor state

        Returns:
            Command specific return value on success, False on failure
        """
        result = False
        info('SensorCommand: {}, sensor {}, channel {}, value {}'.format(command, sensorId, channel, value))
        try:
            if self.pluginManager.is_plugin(sensorId, channel):
                return self.pluginManager.write_value(sensorId, channel, value)
            commands = {'integer': {'function': 'write', 'value_type': int},
                        'value': {'function': 'write', 'value_type': int},
                        'function': {'function': 'setFunctionString', 'value_type': str},
                        'angle': {'function': 'writeAngle', 'value_type': float},
                        'float': {'function': 'writeFloat', 'value_type': float},
                        'volt': {'function': 'writeVolt', 'value_type': float}}
            with self.sensorMutex:
                if sensorId in self.disabledSensors:
                    info('Sensor disabled')
                    return result
                sensor = instance.deviceInstance(sensorId)
                if not sensor:
                    info('Sensor not found')
                    return result
                if command in commands:
                    device = instance.DEVICES[sensorId]
                    info('Sensor found: {}'.format(device))
                    func = getattr(sensor, commands[command]['function'])
                    value = commands[command]['value_type'](value)
                    if channel:
                        result = self.CallDeviceFunction(func, int(channel), value)
                    else:
                        result = self.CallDeviceFunction(func, value)
                    if 'DigitalActuator' in device['type']:
                        manager.updateDeviceState(sensorId, value)
                    return result
                warn('Command not implemented: {}'.format(command))
                return result
        except Exception:
            exception('SensorCommand failed')
        return result
예제 #13
0
class SensorsClient():
    """Class for interfacing with sensors and actuators"""

    def __init__(self):
        """Initialize the bus and sensor info and start monitoring sensor states"""
        self.sensorMutex = RLock()
        self.exiting = Event()
        self.onDataChanged = None
        self.onSystemInfo = None
        self.systemData = []
        self.currentSystemState = []
        self.disabledSensors = {}
        self.disabledSensorTable = "disabled_sensors"
        checkAllBus()
        self.gpio = GPIO()
        manager.addDeviceInstance("GPIO", "GPIO", "GPIO", self.gpio, [], "system")
        manager.loadJsonDevices("rest")
        results = DbManager.Select(self.disabledSensorTable)
        if results:
            for row in results:
                self.disabledSensors[row[0]] = 1
        self.StartMonitoring()

    def SetDataChanged(self, onDataChanged=None, onSystemInfo=None):
        """Set callbacks to call when data has changed
        
        Args:
            onDataChanged: Function to call when sensor data changes
            onSystemInfo: Function to call when system info changes
        """
        self.onDataChanged = onDataChanged
        self.onSystemInfo = onSystemInfo

    def StartMonitoring(self):
        """Start thread monitoring sensor data"""
        ThreadPool.Submit(self.Monitor)

    def StopMonitoring(self):
        """Stop thread monitoring sensor data"""
        self.exiting.set()

    def Monitor(self):
        """Monitor bus/sensor states and system info and report changed data via callbacks"""
        debug('Monitoring sensors and os resources started')
        while not self.exiting.is_set():
            try:
                if not self.exiting.wait(REFRESH_FREQUENCY):
                    self.currentSystemState = []
                    self.MonitorSystemInformation()
                    self.MonitorSensors()
                    self.MonitorBus()
                    if self.currentSystemState != self.systemData:
                        changedSystemData = self.currentSystemState
                        if self.systemData:
                            changedSystemData = [x for x in self.currentSystemState if x not in self.systemData]
                        if self.onDataChanged and changedSystemData:
                            self.onDataChanged(changedSystemData)
                    self.systemData = self.currentSystemState
            except:
                exception('Monitoring sensors and os resources failed')
        debug('Monitoring sensors and os resources finished')

    def MonitorSensors(self):
        """Check sensor states for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.SensorsInfo()

    def MonitorBus(self):
        """Check bus states for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.BusInfo()

    def MonitorSystemInformation(self):
        """Check system info for changes"""
        if self.exiting.is_set():
            return
        self.currentSystemState += self.SystemInformation()

    def SystemInformation(self):
        """Return dict containing current system info, including CPU, RAM, storage and network info"""
        newSystemInfo = []
        try:
            systemInfo = SystemInfo()
            newSystemInfo = systemInfo.getSystemInformation()
        except Exception:
            exception('SystemInformation failed')
        return newSystemInfo

    def CallDeviceFunction(self, func, *args):
        """Call a function for a sensor/actuator device and format the result value type

        Args:
            func: Function to call
            args: Parameters to pass to the function

        Returns:
            True for success, False otherwise.
        """
        result = func(*args)
        if result != None:
            if hasattr(func, "contentType"):
                if func.contentType != M_JSON:
                    value_type = type(result)
                    response = value_type(func.format % result)
                else:
                    response = result
            else:
                response = result
        return response

    def BusInfo(self):
        """Return a dict with current bus info"""
        bus_info = []
        gpio_state = self.gpio.wildcard()
        for key, value in gpio_state.items():
            cayennemqtt.DataChannel.add(bus_info, cayennemqtt.SYS_GPIO, key, cayennemqtt.VALUE, value['value'])
            cayennemqtt.DataChannel.add(bus_info, cayennemqtt.SYS_GPIO, key, cayennemqtt.FUNCTION, value['function'])
        return bus_info

    def SensorsInfo(self):
        """Return a list with current sensor states for all enabled sensors"""
        manager.deviceDetector()
        devices = manager.getDeviceList()
        sensors_info = []
        if devices is None:
            return sensors_info
        for device in devices:
            sensor = instance.deviceInstance(device['name'])
            if 'enabled' not in device or device['enabled'] == 1:
                sensor_types = {'Temperature': {'function': 'getCelsius', 'data_args': {'type': 'temp', 'unit': 'c'}},
                                'Humidity': {'function': 'getHumidityPercent', 'data_args': {'type': 'rel_hum', 'unit': 'p'}},
                                'Pressure': {'function': 'getPascal', 'data_args': {'type': 'bp', 'unit': 'pa'}},
                                'Luminosity': {'function': 'getLux', 'data_args': {'type': 'lum', 'unit': 'lux'}},
                                'Distance': {'function': 'getCentimeter', 'data_args': {'type': 'prox', 'unit': 'cm'}},
                                'ServoMotor': {'function': 'readAngle', 'data_args': {'type': 'analog_actuator'}},
                                'DigitalSensor': {'function': 'read', 'data_args': {'type': 'digital_sensor', 'unit': 'd'}},
                                'DigitalActuator': {'function': 'read', 'data_args': {'type': 'digital_actuator', 'unit': 'd'}},
                                'AnalogSensor': {'function': 'readFloat', 'data_args': {'type': 'analog_sensor'}},
                                'AnalogActuator': {'function': 'readFloat', 'data_args': {'type': 'analog_actuator'}}}
                extension_types = {'ADC': {'function': 'analogReadAllFloat'},
                                    'DAC': {'function': 'analogReadAllFloat'},
                                    'PWM': {'function': 'pwmWildcard'},
                                    'GPIOPort': {'function': 'wildcard'}}
                for device_type in device['type']:
                    try:
                        display_name = device['description']
                    except:
                        display_name = None
                    if device_type in sensor_types:
                        try:
                            sensor_type = sensor_types[device_type]
                            func = getattr(sensor, sensor_type['function'])
                            if len(device['type']) > 1:
                                channel = '{}:{}'.format(device['name'], device_type.lower())
                            else:
                                channel = device['name']
                            cayennemqtt.DataChannel.add(sensors_info, cayennemqtt.DEV_SENSOR, channel, value=self.CallDeviceFunction(func), name=display_name, **sensor_type['data_args'])
                        except:
                            exception('Failed to get sensor data: {} {}'.format(device_type, device['name']))
                    else:
                        try:
                            extension_type = extension_types[device_type]
                            func = getattr(sensor, extension_type['function'])
                            values = self.CallDeviceFunction(func)
                            for pin, value in values.items():
                                cayennemqtt.DataChannel.add(sensors_info, cayennemqtt.DEV_SENSOR, device['name'] + ':' + str(pin), cayennemqtt.VALUE, value, name=display_name)
                        except:
                            exception('Failed to get extension data: {} {}'.format(device_type, device['name']))
        logJson('Sensors info: {}'.format(sensors_info))
        return sensors_info

    def AddSensor(self, name, description, device, args):
        """Add a new sensor/actuator
   
        Args:
            name: Name of sensor to add
            description: Sensor description
            device: Sensor device class
            args: Sensor specific args

        Returns:
            True for success, False otherwise.
        """
        info('AddSensor: {}, {}, {}, {}'.format(name, description, device, args))
        bVal = False
        try:
            sensorAdd = {}
            if name:
                sensorAdd['name'] = name
            if device:
                sensorAdd['device'] = device
            if args:
                sensorAdd['args'] = args
            if description:
                sensorAdd['description'] = description
            with self.sensorMutex:
                retValue = manager.addDeviceJSON(sensorAdd)
            info('Add device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except:
            bVal = False
        return bVal

    def EditSensor(self, name, description, device, args):
        """Edit an existing sensor/actuator
  
        Args:
            name: Name of sensor to edit
            description: New sensor description
            device: New sensor device class
            args: New sensor specific args

        Returns:
            True for success, False otherwise.
        """
        info('EditSensor: {}, {}, {}, {}'.format(name, description, device, args))
        bVal = False
        try:
            sensorEdit = {}
            name = name
            sensorEdit['name'] = name
            sensorEdit['device'] = device
            sensorEdit['description'] = description
            sensorEdit['args'] = args
            with self.sensorMutex:
                retValue = manager.updateDevice(name, sensorEdit)
            info('Edit device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except:
            exception("Edit sensor failed")
            bVal = False
        return bVal

    def RemoveSensor(self, name):
        """Remove an existing sensor/actuator

        Args:
            name: Name of sensor to remove

        Returns:
            True for success, False otherwise.
        """
        bVal = False
        try:
            sensorRemove = name
            with self.sensorMutex:
                retValue = manager.removeDevice(sensorRemove)
            info('Remove device returned: {}'.format(retValue))
            if retValue[0] == 200:
                bVal = True
        except:
            exception("Remove sensor failed")
            bVal = False
        return bVal

    def EnableSensor(self, sensor, enable):
        """Enable a sensor/actuator

        Args:
            sensor: Hash composed from name and device class/type
            enable: 1 to enable, 0 to disable

        Returns:
            True for success, False otherwise.
        """
        info('Enable sensor: ' + str(sensor) + ' ' + str(enable))
        try:
            if sensor is None:
                return False
            if enable is None:
                return False
            with self.sensorMutex:
                if enable == 0:
                    #add item to the list
                    if sensor not in self.disabledSensors:
                        rowId = DbManager.Insert(self.disabledSensorTable, sensor)
                        self.disabledSensors[sensor] = 1
                else:
                    #remove item from the list
                    if sensor in self.disabledSensors:
                        DbManager.Delete(self.disabledSensorTable, sensor)
                        del self.disabledSensors[sensor]
                    #save list
        except Exception as ex:
            error('EnableSensor Failed with exception: '  + str(ex))
            return False
        self.AddRefresh()
        return True

    def GpioCommand(self, command, channel, value):
        """Execute onboard GPIO command

        Args:
            command: Type of command to execute
            channel: GPIO pin
            value: Value to use for writing data

        Returns:
            String containing command specific return value on success, or 'failure' on failure
        """
        info('GpioCommand {}, channel {}, value {}'.format(command, channel, value))
        if command == 'function':
            if value.lower() in ('in', 'input'):
                return str(self.gpio.setFunctionString(channel, 'in'))
            elif value.lower() in ('out', 'output'):
                return str(self.gpio.setFunctionString(channel, 'out'))
        elif command in ('value', ''):
            return self.gpio.digitalWrite(channel, int(value))
        debug('GPIO command failed')
        return 'failure'

    def SensorCommand(self, command, sensorId, channel, value):
        """Execute sensor/actuator command

        Args:
            command: Type of command to execute
            sensorId: Sensor id
            channel: Pin/channel on device, None if there is no channel
            value: Value to use for setting the sensor state

        Returns:
            Command specific return value on success, False on failure
        """
        result = False
        info('SensorCommand: {}, sensor {}, channel {}, value {}'.format(command, sensorId, channel, value))
        try:
            commands = {'integer': {'function': 'write', 'value_type': int},
                        'value': {'function': 'write', 'value_type': int},
                        'function': {'function': 'setFunctionString', 'value_type': str},
                        'angle': {'function': 'writeAngle', 'value_type': float},
                        'float': {'function': 'writeFloat', 'value_type': float},
                        'volt': {'function': 'writeVolt', 'value_type': float}}
            with self.sensorMutex:
                if sensorId in self.disabledSensors:
                    info('Sensor disabled')
                    return result
                sensor = instance.deviceInstance(sensorId)
                if not sensor:
                    info('Sensor not found')
                    return result
                if command in commands:
                    info('Sensor found: {}'.format(instance.DEVICES[sensorId]))
                    func = getattr(sensor, commands[command]['function'])
                    value = commands[command]['value_type'](value)
                    if channel:
                        result = self.CallDeviceFunction(func, int(channel), value)
                    else:
                        result = self.CallDeviceFunction(func, value)
                    return result
                warn('Command not implemented: {}'.format(command))
                return result
        except Exception:
            exception('SensorCommand failed')
        return result
예제 #14
0
"""
This script reads GPIO info. It is intended to be launched via sudo in order to 
read data from files that require root access so the main agent code can run from
a non-root process and only elevate to root when necessary.
"""
import sys
# from myDevices.utils.logger import setInfo, info, error, logToFile
from myDevices.devices.digital.gpio import NativeGPIO

if __name__ == '__main__':
    # Read data using script so it can be called via sudo, sends the data to the main process by writing to stdout
    # setInfo()
    # logToFile()
    i = 1
    while i < len(sys.argv):
        if sys.argv[i] in ['-p', '--pins']:
            import json
            gpio = NativeGPIO()
            print(json.dumps(gpio.wildcard()))
        if sys.argv[i] in ['-c', '--channel']:
            gpio = NativeGPIO()
            i += 1
            channel = int(sys.argv[i])
            print(gpio.getFunction(channel))
        i += 1