Example #1
0
 def __init__(self, serial_con, dip_id, greeting, callbk):
     super().__init__()
     self._serial_con = serial_con
     self._id = dip_id
     self._extended_id = "{}-{}".format(self._id, ID_PREFIX)
     self._greeting = greeting
     self._callbk = callbk
     self._commands = Queue()
     self._serial_logger = serial_logger.getChild(self._id)
     self.log_file = os.path.join(
         os.path.dirname(__file__),
         '{}/{}.log'.format(devices_path, self._id))
     if not self._serial_logger.hasHandlers():
         log_handler = logging.FileHandler(self.log_file)
         log_handler.setFormatter(
             logging.Formatter(fmt='%(asctime)s: %(message)s',
                               datefmt='%m.%d.%Y %I:%M:%S %p'))
         self._serial_logger.addHandler(log_handler)
     if self._loadDeviceInfo():
         self._device = Device(self._extended_id,
                               "iot#fd0e1327-d713-41da-adfb-e3853a71db3b",
                               self._meter_name)
         self._device.addTag("type1", "Ferraris Meter")
         self._device.addTag("type2", "Optical Sensor")
         self.start()
     else:
         self._callbk(self._serial_con.port)
 def devices(self) -> dict:
     query = 'SELECT * FROM {table}'.format(table=__class__._devices_table)
     result = self._executeQuery(query)
     devices = dict()
     for item in result:
         device = Device(item[0], item[1], item[2])
         try:
             for key_value in item[3].split(';'):
                 device.addTag(*key_value.split(':', 1))
         except Exception as ex:
             logger.error(ex)
         devices[device.id] = device
     return devices
 def _evaluate(self, unknown_devices, init):
     missing_devices, new_devices, changed_devices = self._diff(__class__._known_devices, unknown_devices)
     if missing_devices:
         for missing_device_id in missing_devices:
             logger.info("can't find '{}' with id '{}'".format(__class__._known_devices[missing_device_id].get('name'), missing_device_id))
             del __class__.bridge_map[missing_device_id]
             if init:
                 DevicePool.remove(missing_device_id)
             else:
                 Client.disconnect(missing_device_id)
     if new_devices:
         for new_device_id in new_devices:
             name = unknown_devices[new_device_id].get('name')
             logger.info("found '{}' with id '{}'".format(name, new_device_id))
             __class__.bridge_map[new_device_id] = (unknown_devices[new_device_id].get('LIGHT_KEY'), Converter(get_light_gamut(unknown_devices[new_device_id].get('modelid'))))
             device = Device(new_device_id, SEPL_DEVICE_TYPE, name)
             device.addTag('type', unknown_devices[new_device_id].get('type'))
             device.addTag('manufacturer', unknown_devices[new_device_id].get('manufacturername'))
             if init:
                 DevicePool.add(device)
             else:
                 Client.add(device)
     if changed_devices:
         for changed_device_id in changed_devices:
             device = DevicePool.get(changed_device_id)
             name = unknown_devices[changed_device_id].get('name')
             if not name == device.name:
                 device.name = name
                 if init:
                     DevicePool.update(device)
                 else:
                     Client.update(device)
                 logger.info("name of '{}' changed to {}".format(changed_device_id, name))
     __class__._known_devices = unknown_devices
 def get(self, id_str) -> Device:
     if type(id_str) is not str:
         raise TypeError("id must be a string but got '{}'".format(
             type(id_str)))
     query = 'SELECT {type}, {name}, {tags} FROM {table} WHERE {id}="{id_v}"'.format(
         table=__class__._devices_table,
         type=__class__._type_field[0],
         name=__class__._name_field[0],
         tags=__class__._tags_field[0],
         id=__class__._id_field[0],
         id_v=id_str)
     result = self._executeQuery(query)
     if result:
         device = Device(id_str, result[0][0], result[0][1])
         try:
             for key_value in result[0][2].split(';'):
                 device.addTag(*key_value.split(':', 1))
         except Exception as ex:
             logger.error(ex)
         return device
Example #5
0
 def devices() -> dict:
     query = 'SELECT * FROM {table}' \
             'WHERE status = 1'.format(
         table=__class__._devices_table
     )
     result = DB._executeQuery(query)
     devices = dict()
     if result:
         for r in result:
             device = Device(str([0]), r[2], r[1])
             devices[device.id] = device
     return devices
Example #6
0
 def get(id):
     query = """
             SELECT * FROM endpoints
             WHERE id = {id}
             """.format(id=id)
     result = DB._executeQuery(query)
     if result:
         result = result[0]
         new_device = Device(str(result[0]), result[2], result[1])
         return new_device
     else:
         return None
Example #7
0
 def _evaluate(self, unknown_devices):
     missing_devices, new_devices, changed_devices = self._diff(__class__._known_devices, unknown_devices)
     if missing_devices:
         for missing_device_id in missing_devices:
             logger.info("can't find '{}' with id '{}'".format(__class__._known_devices[missing_device_id].get('label'), missing_device_id))
             try:
                 Client.delete(missing_device_id)
             except AttributeError:
                 DevicePool.remove(missing_device_id)
     if new_devices:
         for new_device_id in new_devices:
             name = unknown_devices[new_device_id].get('label')
             logger.info("found '{}' with id '{}'".format(name, new_device_id))
             device = Device(new_device_id, SEPL_DEVICE_TYPE, name)
             product = unknown_devices[new_device_id].get('product')
             device.addTag('type', 'Extended color light')
             device.addTag('product', product.get('name'))
             device.addTag('manufacturer', product.get('company'))
             try:
                 Client.add(device)
             except AttributeError:
                 DevicePool.add(device)
     if changed_devices:
         for changed_device_id in changed_devices:
             seconds_since_seen = unknown_devices[changed_device_id].get('seconds_since_seen')
             if seconds_since_seen >= 60:
                 try:
                     Client.disconnect(changed_device_id)
                 except AttributeError:
                     DevicePool.remove(changed_device_id)
                 del unknown_devices[changed_device_id]
             else:
                 device = DevicePool.get(changed_device_id)
                 name = unknown_devices[changed_device_id].get('label')
                 if not name == device.name:
                     device.name = name
                     try:
                         Client.update(device)
                     except AttributeError:
                         DevicePool.update(device)
                     logger.info("name of '{}' changed to {}".format(changed_device_id, name))
     __class__._known_devices = unknown_devices
tests = scenario[6]

logger.info('###### initiation phase ######')

id_1 = 'asdsdfsf24t'
id_2 = '3g46h4h6h436h'
id_3 = '46j5j67j6rt'
id_4 = '3h6j6i8i7rer5'

device_manager = DevicePool

if 0 in tests:
    logger.info('------ populate device manager ------')
    device_manager.add(
        Device(id_1, 'iot#d66ec9bc-e37f-4f35-a788-027301aad6c2',
               'Dummy Device 1'))
    device_2 = Device(id_2, 'iot#d66ec9bc-e37f-4f35-a788-027301aad6c2',
                      'Dummy Device 2')
    device_2.addTag('type', 'Dummy')
    device_manager.add(device_2)
    device_manager.add(
        Device(id_3, 'iot#d66ec9bc-e37f-4f35-a788-027301aad6c2',
               'Dummy Device 3'))

if __name__ == '__main__':
    connector_client = Client(device_manager)

    logger.info('###### runtime phase ######')

    if 1 in tests:
        time.sleep(0.5)
Example #9
0
class DeviceController(Thread):
    def __init__(self, serial_con, dip_id, greeting, callbk):
        super().__init__()
        self._serial_con = serial_con
        self._id = dip_id
        self._extended_id = "{}-{}".format(self._id, ID_PREFIX)
        self._greeting = greeting
        self._callbk = callbk
        self._commands = Queue()
        self._serial_logger = serial_logger.getChild(self._id)
        self.log_file = os.path.join(
            os.path.dirname(__file__),
            '{}/{}.log'.format(devices_path, self._id))
        if not self._serial_logger.hasHandlers():
            log_handler = logging.FileHandler(self.log_file)
            log_handler.setFormatter(
                logging.Formatter(fmt='%(asctime)s: %(message)s',
                                  datefmt='%m.%d.%Y %I:%M:%S %p'))
            self._serial_logger.addHandler(log_handler)
        if self._loadDeviceInfo():
            self._device = Device(self._extended_id,
                                  "iot#fd0e1327-d713-41da-adfb-e3853a71db3b",
                                  self._meter_name)
            self._device.addTag("type1", "Ferraris Meter")
            self._device.addTag("type2", "Optical Sensor")
            self.start()
        else:
            self._callbk(self._serial_con.port)

    def _loadDeviceInfo(self):
        conf = devices_db.getDevice(self._id)
        if not conf:
            logger.warning("no configuration found for device '{}'".format(
                self._id))
            if devices_db.addDevice(self._id):
                logger.info("created configuration for device '{}'".format(
                    self._id))
                conf = devices_db.getDevice(self._id)
            else:
                logger.error(
                    "could not create configuration for device '{}'".format(
                        self._id))
        if conf:
            self._mode = Mode(conf['mode'])
            self._conf = {
                Mode.interval: {
                    'conf_a': conf['lb'],
                    'conf_b': conf['rb']
                },
                Mode.average: {
                    'conf_a': conf['nat'],
                    'conf_b': conf['lld']
                }
            }
            self._dt = conf['dt']
            self._ndt = conf['ndt']
            self._strt = conf['strt']
            self._rpkwh = conf['rpkwh']
            self._kwh = float(conf['kwh'])
            self._meter_name = conf['name']
            if not self._meter_name:
                self._meter_name = "Ferraris Sensor ({})".format(self._id)
            logger.info("loaded configuration for device '{}'".format(
                self._id))
            return True
        logger.error("could not load configuration for device '{}'".format(
            self._id))
        return False

    def _writeSerialLog(self, data, src=None):
        if type(data) is not str:
            data = data.decode()
        data = data.replace('\n', '').replace('\r', '')
        if src == 'D':
            self._serial_logger.info('> {}'.format(data))
        elif src == 'C':
            self._serial_logger.info('< {}'.format(data))
        else:
            self._serial_logger.info('# {}'.format(data))

    def _waitFor(self, char, retries=5):
        try:
            for retry in range(retries):
                msg = self._serial_con.readline()
                logger.debug(msg)
                if char in msg.decode():
                    return msg.decode()
        except Exception as ex:
            logger.error(ex)
        return None

    def _closeConnection(self):
        self._serial_con.close()
        self._writeSerialLog('serial connection closed')
        self._callbk(self._serial_con.port)

    def run(self):
        logger.debug("starting serial controller for device '{}'".format(
            self._id))
        self._writeSerialLog('serial connection open')
        self._writeSerialLog(self._greeting, 'D')
        if self._waitFor('RDY'):
            self._writeSerialLog('RDY', 'D')
            logger.info("started serial controller for device '{}'".format(
                self._id))
            logger.debug(self._serial_con)
            if self._configureDevice(init=True):
                try:
                    Client.add(self._device)
                except AttributeError:
                    DevicePool.add(self._device)
                if self._strt:
                    self.startDetection()
                while True:
                    try:
                        command, callbk, kwargs = self._commands.get(timeout=1)
                        if command != self._stopAction:
                            if kwargs:
                                command(callbk, **kwargs)
                            else:
                                command(callbk)
                        else:
                            callbk(409)
                    except Empty:
                        pass
                    except __class__.Interrupt:
                        break
                try:
                    Client.disconnect(self._device)
                except AttributeError:
                    DevicePool.remove(self._device)
        else:
            logger.error("device '{}' not ready".format(self._id))
        self._closeConnection()
        logger.info("serial controller for device '{}' exited".format(
            self._id))

    class Interrupt(Exception):
        pass

    #---------- getters and setters ----------#

    def getConf(self):
        return {
            'mode': self._mode.value,
            'conf': {
                Mode.interval.value: self._conf[Mode.interval],
                Mode.average.value: self._conf[Mode.average]
            },
            'dt': self._dt,
            'ndt': self._ndt
        }

    def getSettings(self):
        return {
            'strt': self._strt,
            'rpkwh': self._rpkwh,
            'tkwh': self._kwh,
            'name': self._meter_name
        }

    def setConf(self, callbk, mode, conf_a, conf_b, dt, ndt):
        success = False
        if Mode(mode) == Mode.interval:
            success = devices_db.updateDevice(self._id,
                                              mode=Mode(mode).value,
                                              lb=int(conf_a),
                                              rb=int(conf_b),
                                              dt=int(dt),
                                              ndt=int(ndt))
        elif Mode(mode) == Mode.average:
            success = devices_db.updateDevice(self._id,
                                              mode=Mode(mode).value,
                                              nat=int(conf_a),
                                              lld=int(conf_b),
                                              dt=int(dt),
                                              ndt=int(ndt))
        if success:
            self._mode = Mode(mode)
            self._conf[self._mode]['conf_a'] = int(conf_a)
            self._conf[self._mode]['conf_b'] = int(conf_b)
            self._dt = int(dt)
            self._ndt = int(ndt)
            self._commands.put((self._configureDevice, callbk, None))

    def setSettings(self, rpkwh, kwh, name):
        if type(kwh) is str:
            kwh = kwh.replace(',', '.')
        if devices_db.updateDevice(self._id,
                                   rpkwh=int(rpkwh),
                                   kwh=float(kwh),
                                   name=str(name)):
            self._rpkwh = int(rpkwh)
            self._kwh = float(kwh)
            self._meter_name = str(name)
            if not self._device.name == self._meter_name:
                self._device.name = self._meter_name
                try:
                    Client.update(self._device)
                except AttributeError:
                    DevicePool.update(self._device)

    def setAutoStart(self, state):
        if devices_db.updateDevice(self._id, strt=int(state)):
            self._strt = int(state)

    def _calcAndWriteTotal(self, kwh):
        kwh = kwh + self._kwh
        devices_db.updateDevice(self._id, kwh=str(kwh))
        self._kwh = kwh

    def _savePlotData(self, data):
        try:
            with open(
                    os.path.join(os.path.dirname(__file__),
                                 '{}/{}.plot'.format(devices_path, self._id)),
                    'w') as file:
                file.write(json.dumps(data))
        except Exception as ex:
            logger.error("storing plot data for '{}' failed - {}".format(
                self._id, ex))

    def getPlotData(self):
        try:
            with open(
                    os.path.join(os.path.dirname(__file__),
                                 '{}/{}.plot'.format(devices_path, self._id)),
                    'r') as file:
                return json.loads(file.read())
        except Exception as ex:
            logger.error("loading plot data for '{}' failed - {}".format(
                self._id, ex))

    #---------- commands ----------#

    def _configureDevice(self, callbk=None, init=False):
        try:
            self._serial_con.write(b'CONF\n')
            self._writeSerialLog('CONF', 'C')
            msg = self._waitFor(':')
            if msg:
                self._writeSerialLog(msg, 'D')
                conf = '{}:{}:{}:{}:{}\n'.format(
                    self._mode.value, self._conf[self._mode]['conf_a'],
                    self._conf[self._mode]['conf_b'], self._dt, self._ndt)
                self._serial_con.write(conf.encode())
                self._writeSerialLog(conf, 'C')
                if self._waitFor(conf.replace('\n', '')):
                    self._writeSerialLog(conf, 'D')
                    if self._waitFor('RDY'):
                        self._writeSerialLog('RDY', 'D')
                        logger.info("configured device {}".format(self._id))
                        if callbk:
                            callbk(200)
                        return True
                    else:
                        logger.error("device '{}' not ready".format(self._id))
                else:
                    logger.error("device '{}' could not be configured".format(
                        self._id))
            else:
                logger.error(
                    "device '{}' did not enter configuration mode".format(
                        self._id))
        except (SerialException, SerialTimeoutException, ValueError) as ex:
            logger.error(ex)
            if callbk:
                callbk(500)
        if init:
            return False
        raise __class__.Interrupt

    def readSensor(self, callbk):
        self._commands.put((self._readSensor, callbk, None))

    def _readSensor(self, callbk):
        try:
            self._serial_con.write(b'MR\n')
            self._writeSerialLog('MR', 'C')
            callbk(200)
            while True:
                msg = self._serial_con.readline()
                if msg:
                    self._writeSerialLog(msg, 'D')
                try:
                    command, callbk, kwargs = self._commands.get_nowait()
                    if command == self._stopAction:
                        if self._stopAction(callbk):
                            return True
                        else:
                            break
                    else:
                        callbk(409)
                        self._writeSerialLog('busy - operation not possible')
                except Empty:
                    pass
        except (SerialException, SerialTimeoutException) as ex:
            logger.error(ex)
            callbk(500)
        raise __class__.Interrupt

    def plotReadings(self, callbk):
        self._commands.put((self._plotReadings, callbk, None))

    def _plotReadings(self, callbk):
        try:
            self._serial_con.write(b'NDMR\n')
            self._writeSerialLog('NDMR', 'C')
            callbk(200)
            self._writeSerialLog('device output suppressed during operation')
            data = list()
            count = 0
            while True:
                msg = self._serial_con.readline()
                if msg:
                    data.append([count, msg])
                    count += 1
                try:
                    command, callbk, kwargs = self._commands.get_nowait()
                    if command == self._stopAction:
                        self._serial_con.write(b'STP\n')
                        self._writeSerialLog('STP', 'C')
                        if self._waitFor('RDY'):
                            self._writeSerialLog('RDY', 'D')
                            for x in range(len(data)):
                                data[x][1] = int(data[x][1].decode().replace(
                                    '\n', '').replace('\r', ''))
                            self._savePlotData(data)
                            callbk(200, {'res': data})
                            return True
                        else:
                            callbk(500)
                            break
                    else:
                        callbk(409)
                        self._writeSerialLog('busy - operation not possible')
                except Empty:
                    pass
        except (SerialException, SerialTimeoutException) as ex:
            logger.error(ex)
            callbk(500)
        raise __class__.Interrupt

    def findBoundaries(self, callbk):
        self._commands.put((self._findBoundaries, callbk, None))

    def _findBoundaries(self, callbk):
        try:
            self._serial_con.write(b'FB\n')
            self._writeSerialLog('FB', 'C')
            callbk(200)
            self._writeSerialLog('device output suppressed during operation')
            while True:
                try:
                    command, callbk, kwargs = self._commands.get(timeout=1)
                    if command == self._stopAction:
                        self._serial_con.write(b'STP\n')
                        self._writeSerialLog('STP', 'C')
                        result = self._waitFor(':')
                        if self._waitFor('RDY'):
                            self._writeSerialLog('RDY', 'D')
                            callbk(200, {
                                'res':
                                result.replace('\n', '').replace('\r', '')
                            })
                            return True
                        else:
                            callbk(500)
                            break
                    else:
                        self._writeSerialLog('busy - operation not possible')
                        callbk(409)
                except Empty:
                    pass
        except (SerialException, SerialTimeoutException) as ex:
            logger.error(ex)
            callbk(500)
        raise __class__.Interrupt

    def buildHistogram(self, callbk, lb, rb, res):
        self._commands.put((self._buildHistogram, callbk, {
            'lb': lb,
            'rb': rb,
            'res': res
        }))

    def _buildHistogram(self, callbk, lb, rb, res):
        try:
            self._serial_con.write(b'HST\n')
            self._writeSerialLog('HST', 'C')
            msg = self._waitFor(':')
            if msg:
                self._writeSerialLog(msg, 'D')
                conf = '{}:{}:{}\n'.format(lb, rb, res)
                self._serial_con.write(conf.encode())
                self._writeSerialLog(conf, 'C')
                resp = self._waitFor(':')
                self._writeSerialLog(resp, 'D')
                if 'NaN' not in resp:
                    callbk(200)
                    self._writeSerialLog(
                        'device output suppressed during operation')
                    while True:
                        try:
                            command, callbk, kwargs = self._commands.get(
                                timeout=1)
                            if command == self._stopAction:
                                self._serial_con.write(b'STP\n')
                                self._writeSerialLog('STP', 'C')
                                result = self._waitFor(':')
                                if self._waitFor('RDY'):
                                    self._writeSerialLog('RDY', 'D')
                                    callbk(
                                        200, {
                                            'res':
                                            result.replace('\n', '').replace(
                                                '\r', '')
                                        })
                                    return True
                                else:
                                    callbk(500)
                                    break
                            else:
                                self._writeSerialLog(
                                    'busy - operation not possible')
                                callbk(409)
                        except Empty:
                            pass
                else:
                    logger.error(
                        "could not set histogram settings for device '{}'".
                        format(self._id))
                    callbk(500)
            else:
                logger.error(
                    "device '{}' did not enter histogram settings mode".format(
                        self._id))
                callbk(500)
        except (SerialException, SerialTimeoutException) as ex:
            logger.error(ex)
            callbk(500)
        raise __class__.Interrupt

    def stopAction(self, callbk):
        self._commands.put((self._stopAction, callbk, None))

    def _stopAction(self, callbk):
        try:
            self._serial_con.write(b'STP\n')
            self._writeSerialLog('STP', 'C')
            if self._waitFor('RDY'):
                self._writeSerialLog('RDY', 'D')
                callbk(200)
                return True
        except SerialTimeoutException:
            callbk(500)
            return False

    def startDetection(self, callbk=None):
        self._commands.put((self._startDetection, callbk, None))

    def _startDetection(self, callbk=None):
        if int(self._rpkwh) > 0:
            #ws = int(3600000 / int(self._rpkwh))
            #kWh = ws / 3600000
            try:
                self._serial_con.write(b'STRT\n')
                self._writeSerialLog('STRT', 'C')
                if callbk:
                    callbk(200)
                while True:
                    msg = self._serial_con.readline()
                    if 'DET' in msg.decode():
                        self._calcAndWriteTotal(1 / int(self._rpkwh))
                        """
                        Client.event(
                            self._extended_id,
                            'detection',
                            json.dumps({
                                'value': self._kwh,
                                'unit': 'kWh',
                                'time': '{}Z'.format(datetime.datetime.utcnow().isoformat())
                            }),
                            block=False
                        )
                        """
                    elif 'CAL' in msg.decode():
                        self._writeSerialLog('CAL', 'D')
                    try:
                        command, callbk, kwargs = self._commands.get_nowait()
                        if command == self._stopAction:
                            if self._stopAction(callbk):
                                return True
                            else:
                                break
                        else:
                            self._writeSerialLog(
                                'busy - operation not possible')
                            callbk(409)
                    except Empty:
                        pass
            except (SerialException, SerialTimeoutException) as ex:
                logger.error(ex)
                if callbk:
                    callbk(500)
            raise __class__.Interrupt
        else:
            logger.warning(
                "detection for device '{}' failed - rounds/kWh not set".format(
                    self._id))
            self._writeSerialLog('rotations/kWh not set')
            if callbk:
                callbk(500)

    def startDebug(self, callbk):
        self._commands.put((self._startDebug, callbk, None))

    def _startDebug(self, callbk):
        try:
            self._serial_con.write(b'STRT\n')
            self._writeSerialLog('STRT', 'C')
            callbk(200)
            while True:
                msg = self._serial_con.readline()
                if msg.decode() != '':
                    self._writeSerialLog(msg, 'D')
                try:
                    command, callbk, kwargs = self._commands.get_nowait()
                    if command == self._stopAction:
                        if command(callbk):
                            return True
                        else:
                            break
                    else:
                        self._writeSerialLog('busy - operation not possible')
                        callbk(409)
                except Empty:
                    pass
        except (SerialException, SerialTimeoutException) as ex:
            logger.error(ex)
            callbk(500)
        raise __class__.Interrupt

    def haltController(self, callbk=None):
        self._commands.put((self._haltController, callbk, None))

    def _haltController(self, callbk=None):
        if callbk:
            callbk(200)
        raise __class__.Interrupt
try:
    from connector_client.modules.http_lib import Methods as http
    from connector_client.modules.device_pool import DevicePool
    from connector_client.client import Client
    from connector_client.device import Device
    from configuration import SM_ID, SM_NAME, SM_MANUFACTURER, SM_TYPE, SEPL_DEVICE_TYPE, SEPL_SERVICE
    from smart_meter_serial import SmartMeterSerial
    from logger import root_logger
except ImportError as ex:
    exit("{} - {}".format(__name__, ex.msg))
import datetime, json

logger = root_logger.getChild(__name__)

smart_meter = Device(SM_ID, SEPL_DEVICE_TYPE, SM_NAME)
if SM_TYPE:
    smart_meter.addTag('type', SM_TYPE)
if SM_MANUFACTURER:
    smart_meter.addTag('manufacturer', SM_MANUFACTURER)
DevicePool.add(smart_meter)

sm_serial = SmartMeterSerial()


def getReading(source):
    payload = dict()
    while True:
        readings = source.read()
        if readings:
            payload['value'] = float(readings['1.8.0'][0])