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
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
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
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)
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])