def readTags(self, *tags): """ Прочитать список тегов. @param tags: Список объектов тегов. @return: True/False. """ if not tags: log.warning(u'Не определен список тегов для чтения') return False # Контроль что все теги соответствуют узлу is_my_tags_list = [tag.getNode().GetPassport() == self.GetPassport() for tag in tags] is_my_tags = all(is_my_tags_list) if not is_my_tags: not_my_tags = [tags[i].name for i, is_my_tag in enumerate(is_my_tags_list) if not is_my_tag] log.error(u'Не соответствие читаемых тегов %s Memory источнику данных' % not_my_tags) return False for tag in tags: # Все теги Memory узла являются вычисляемыми. # Выражение для вычисления записывается в 'address' expression = tag.GetResource().get('address', None) if not expression: log.warning(u'Не определена функция вычисляемого тега <%s> для определения значения' % tag.getName()) value = None else: self.setEnv(TAG=tag) # log.debug(u'Обработка вычисляемого тега <%s>. Выражение <%s>' % (tag.getName(), expression)) value = self.read_value(expression) tag.setCurValue(value) return True
def _signal_loop(self, *warg): """ Диспетчер сигналов. """ while True: # Обрабатываем очередь if not self._eventLoopLst.isSet(): # Ждем 5 сек, если очередь занята self._eventLoopLst.wait(0.5) if not self._eventLoopLst.isSet(): log.warning( u'Диспетчер ядра не может получить доступ к очереди сигналов.' ) else: # Если установлен признак остановки, то выходим из цикла if self.__stop: break self._parse_signal_lst() else: # Если установлен признак остановки, то выходим из цикла if self.__stop: break self._parse_signal_lst() try: time.sleep(0.001) except: log.error(u'*** EXCEPTION time.sleep(0.001) ***') break
def ReCodeString(String_, StringCP_, NewCP_): """ Перекодировать из одной кодировки в другую. @param String_: Строка. @param StringCP_: Кодовая страница строки. @param NewCP_: Новая кодовая страница строки. """ if NewCP_.upper() == 'UNICODE': # Кодировка в юникоде. if isinstance(String_, str): return unicode(String_, StringCP_) else: return String_ if NewCP_.upper() == 'OCT' or NewCP_.upper() == 'HEX': # Закодировать строку в восьмеричном/шестнадцатеричном виде. return OctHexString(String_, NewCP_) if isinstance(String_, str): string = unicode(String_, StringCP_) elif isinstance(String_, unicode): string = String_ try: return string.encode(NewCP_) except: log.error('Decode string error: <%s> -> <%s>.' % (StringCP_, NewCP_)) return string
def setPrintOptions(self, args, bShow=True): """ Установить параметры печати из списка аргументов. @param args: Список аргументов. @param bShow: Обновить в диалоговом окне контролы? """ if isinstance(args, dict): self.args = args elif isinstance(args, list): self.args = dict(args) else: log.error(u'Wrong type arguments <%s>' % type(args)) return for option, arg in self.args.items(): if option in ('--printer', ): self.printer = arg elif option in ('--A4', '--a4'): self.size = 'a4' elif option in ('--A3', '--a3'): self.size = 'a3' elif option in ('--portrait', '-P'): self.orientation = 'portrait' elif option in ('--landscape', '-L'): self.orientation = 'landscape' elif option in ('--width', '-w'): self.width = int(arg) elif option in ('--height', '-h'): self.height = int(arg) elif option in ('--all', ): self.order = 'all' elif option in ('--even', ): self.order = 'even' elif option in ('--odd', ): self.order = 'odd' elif option in ('--pages', ): self.pages = arg elif option in ('--copies', ): self.copies = int(arg) elif option in ('--left', '-l'): self.left = int(arg) elif option in ('--right', '-r'): self.right = int(arg) elif option in ('--top', '-t'): self.top = int(arg) elif option in ('--bottom', '-b'): self.bottom = int(arg) elif option in ('--lines', ): self.lines = int(arg) elif option in ('--use_font', ): self.use_font = True elif option in ('--dlg', ): pass elif option in ('--file', ): self.print_filename = arg else: log.warning(u'Not defined option <%s>' % option) if bShow: self.showPrintOptions()
def readTags(self, *tags): """ Прочитать список тегов. @param tags: Список объектов тегов. @return: True/False. """ if not tags: log.warning(u'Не определен список тегов для чтения') return False # else: # log.debug(u'Чтение тегов %s из OPC <%s>' % (str(tags), self.getName())) # Контроль что все теги соответствуют узлу is_my_tags_list = [ tag.getNode().GetPassport() == self.GetPassport() for tag in tags ] is_my_tags = all(is_my_tags_list) if not is_my_tags: not_my_tags = [ tags[i].name for i, is_my_tag in enumerate(is_my_tags_list) if not is_my_tag ] log.error( u'Не соответствие читаемых тегов %s OPC источнику данных' % not_my_tags) return False topic = self.getTopic() addresses = [topic + tag.getAddress() for tag in tags] values = self.read_values(addresses) for i, value in enumerate(values): tags[i].setCurValue(value) return True
def GetAssociateFld(self, key, fld_name): """ Возвращает значение определенного поля ассоциации. @type key: C{tuple} @param key: Ключ объекта в словаре. @type fld_name: C{string} @param fld_name: Имя поля. """ if key in self._model: vals = self._model[key][0] # Определяем индекс поля try: indx = list(self.assc_val).index(fld_name) value = vals[indx] log.debug(u'>>> IN GetAssociateFld FIND FIELD Value = %s' % value) return value except: log.error( u'>>> fld_name value ERROR in GetAssociateFld fld_name: %s' % fld_name) log.fatal(u'>>> asscDict = %s' % self._model) return None
def __init__(self, parent, Context_=None, ProjectRoot_=None): """ Конструктор интерфейса. """ # Вызываем конструктор базового класса icobjectinterface.icObjectInterface.__init__(self, parent, resource) try: viewer = self.GetNameObj('view_treectrl') if Context_ is None: Context_ = ic_user.getKernel().GetContext() variables = self._contextConvert(Context_) viewer.LoadTree(variables) except: log.error( u'Ошибка инициализации дерева просмотра хранилища переменных.') self._project_root = ProjectRoot_ if self._project_root: try: env_grid = self.GetNameObj('env_grid') env_dict = self._project_root.prj_res_manager.getPrjEnv() env_list = env_dict.items() env_list.sort() log.debug('Environment list: <%s>' % env_list) env_grid.setTable(env_list) except: log.error( u'Ошибка инициализации грида редактирования дополнительных атрибутов проекта.' )
def getScanClassPsp(self): """ Паспорт класса сканирования данных SCADA. @return: Паспорт или None в случае ошибки. """ log.error(u'Функция getScanClassPsp не реализована в <%s>' % self.__class__.__name__) return None
def getNodePsp(self): """ Паспорт узла-источника данных SCADA. @return: Паспорт или None в случае ошибки. """ log.error(u'Функция getNodePsp не реализована в <%s>' % self.__class__.__name__) return None
def read_value(self, address): """ Чтение значения по адресу. @param address: Адрес значения в узле. @return: Запрашиваемое значение или None в случае ошибки чтения. """ log.error(u'Функция чтения данных по адресу не реализована в <%s>' % self.__class__.__name__) return None
def readTags(self, *tags): """ Прочитать список тегов. @param tags: Список объектов тегов. @return: True/False. """ log.error(u'Функция чтения списка тегов не реализована в <%s>' % self.__class__.__name__) return False
def read_values(self, addresses): """ Чтение значений по адресам. @param addresses: Список адресов значений в узле. @return: Список запрашиваемых значений или None в случае ошибки чтения. """ log.error( u'Функция чтения списка данных по адресу не реализована в <%s>' % self.__class__.__name__) return None
def write_value(self, address, value): """ Запись значения по адресу. @param address: Адрес значения в узле. @param value: Записываемое значение. @return: True - запись прошла успешно/False - ошибка. """ log.error(u'Функция записи данных по адресу не реализована в <%s>' % self.__class__.__name__) return None
def outDevice(msg, Device_=IC_CONSOLE): """ Вывод на устройство регистрации специальных сообщений. @type msg: C{string} @param msg: Сообщение об ошибке. @type Device_: C{int} @param Device_: Указание устройства вывода. """ if Device_ & IC_CONSOLE: try: print(msg) except: return False if Device_ & IC_CONSOLE_INFO: try: log.info(msg) except: return False if Device_ & IC_CONSOLE_ERR: try: log.error(msg) except: return False if Device_ & IC_CONSOLE_WARN: try: log.warning(msg) except: return False if Device_ & IC_CONSOLE_DBG: try: log.debug(msg) except: return False if Device_ & IC_FILE: try: log_file = None log_file = open(IC_LOG_FILE_DEFAULT, 'w+') log_file.write(msg) log_file.close() except: if log_file: log_file.close() return False if Device_ & IC_MSG_INFO: import ic.dlg ic.dlg.ic_dlg.icMsgBox(u'ВНИМАНИЕ', msg) if Device_ & IC_MSG_ERR: import ic.dlg ic.dlg.ic_dlg.icErrBox(u'ОШИБКА', msg) return True
def getNode(self, node_psp=None): """ Объект узла-источника данных SCADA. @param node_psp: Паспорт узла-источника данных SCADA. Если не определено, то задается функцией self.getNodePsp. @return: Объект узла-источника данных SCADA или None в случае ошибки. """ log.error(u'Функция getNode не реализована в <%s>' % self.__class__.__name__) return None
def ctrlVal(typ, text): """ Функция проверяет соответствие значения определенному типу. @type typ: C{int} @param typ: Тип значения, к котророму необходимо преобразовать. @type text: C{string} @param text: Значение в строковом представлении. @return: Код контроля. None означает синтаксическую ошибку. """ if typ in (EDT_TEXTFIELD, EDT_PY_SCRIPT, EDT_CHOICE): value = text else: try: value = eval(text) except: log.error('eval(text): text=<%s>' % text) return None ret = coderror.IC_CTRL_FAILED # Текст if typ in (EDT_TEXTFIELD, EDT_PY_SCRIPT, EDT_CHOICE) and type(value) in (str, unicode): ret = coderror.IC_CTRL_OK # Список в синтаксисе Python. Пример: ['1', 2, 'abc'] elif typ == EDT_TEXTLIST and isinstance(value, list): ret = coderror.IC_CTRL_OK # Словарь elif typ in (EDT_TEXTDICT, EDT_DICT, EDT_FONT) and isinstance(value, dict): ret = coderror.IC_CTRL_OK # Числовое поле elif typ in (EDT_NUMBER, EDT_CHECK_BOX, EDT_COMBINE) and type(value) in (int, float, bool): ret = coderror.IC_CTRL_OK # Редактор цветов wxColour. elif typ == EDT_COLOR and value is None: ret = coderror.IC_CTRL_OK elif typ == EDT_COLOR and ((type(value) == wx.Colour) or (isinstance(value, tuple) and len(value) == 3)): ret = coderror.IC_CTRL_OK # Редактор координат точки wx.Point. elif typ == EDT_POINT and type(value) in (tuple, type(wx.Point( 0, 0))) and len(value) == 2: ret = coderror.IC_CTRL_OK # Редактор размеров окон wx.Size. elif typ == EDT_SIZE and type(value) in (tuple, type(wx.Size( 0, 0))) and len(value) == 2: ret = coderror.IC_CTRL_OK return ret
def _get_panel_obj_addresses(self, data_list=None, *ctrl_names): """ Получить адреса объектов указанных в data_name свойстве контролов панели. Адреса объектов указываются как <Имя_движка.Имя_объекта_в_движке>. @param data_list: Список для заполнения. Если не определен то создается новый список. @param ctrl_names: Взять только контролы с именами... Если имена контролов не определены, то обрабатываются контролы, указанные в соответствиях (accord). @return: Заполненный список [(контрол, адрес тега),...) """ result = list() if data_list is None else data_list if not ctrl_names: ctrl_names = self.getAllChildrenNames() for ctrlname in ctrl_names: ctrl = self.FindObjectByName(ctrlname) if issubclass(ctrl.__class__, icwidget.icWidget) and ctrl.isEnabled(): if issubclass(ctrl.__class__, icwxpanel.icWXPanel): log.warning( u'ВНИМАНИЕ! Для обновлений контролов в панели <%s>, панель должна быть SCADAPanel' % ctrlname) if issubclass(ctrl.__class__, self.__class__): data = ctrl._get_panel_obj_addresses( data_list, *ctrl_names) result += data else: address = ctrl.getDataName() if address: if self.is_address(address): # Сразу разделить адрес на имя движка и имя объекта result.append( (ctrl, tuple(address.split(ADDRESS_DELIMETER)))) else: log.error( u'Ошибка адресации <%s> в контроле <%s>. Адреса указываются как <Имя_движка.Имя_объекта_в_движке>' % (address, ctrlname)) else: log.warning(u'Контрол <%s> не может принимать данные' % ctrlname) return result
def findSCADAObject(self, obj_address): """ Поиск объекта по его адресу. @param obj_address: Адрес объекта. Адреса объектов указываются как <Имя_движка.Имя_объекта_в_движке>. @return: Найденный объект или None, если объект не найден. """ if type(obj_address) not in (str, unicode): log.error(u'Не корректный тип адреса <%s> объекта SCADA движка' % obj_address.__class__.__name__) return None engine_name, obj_name = obj_address.split(ADDRESS_DELIMETER) if engine_name and obj_name: engine = self.findSCADAEngine(engine_name) if engine: obj = engine.findObject(obj_name) return obj return None
def connect(self, host=None, opc_server=None): """ Создание объекта OPC клиента. @param host: Хост OPC сервера для возможности удаленного подключения (через DCOM) к OPC серверу. Если не определен, то берется из описания компонента. @param opc_server: Имя OPC сервера. Если не определен, то берется из описания компонента. @return: Объект OPC сервера. """ if host is None: host = self.getHost() if opc_server is None: opc_server = self.getOPCServer() if type(host) not in (None.__class__, str, unicode): log.error(u'Не корректный тип хоста OPC сервера <%s>' % type(host)) return None is_local_opc = self.is_localhost(host) if is_local_opc: log.info(u'OPC сервер находится локально') opc = OpenOPC.client() else: log.info(u'OPC сервер находится на <%s>' % host) opc = OpenOPC.open_client(host) if opc is None: log.error(u'Не возможно создать объект клиента OPC. Хост <%s>' % host) return None # Список серверов OPC servers = opc.servers() if opc_server not in servers: log.warning(u'Сервер <%s> не найден среди %s' % (opc_server, servers)) self.disconnect(opc) return None # Соедиенение с сервером opc.connect(opc_server) return opc
def synchroPrj(self, Refresh_=False): """ Синхронизация дерева проекта с изменениями другими программистами. @param Refresh_: указание принудительного обновления дерева проекта. """ prj_file = self.getPrjFileName() if prj_file: cur_prj_res_time = ic_file.GetMakeFileTime(prj_file) cur_prj_res_size = ic_file.GetFileSize(prj_file) if (cur_prj_res_time != self.prj_res_time) or \ (cur_prj_res_size != self.prj_res_size) or \ Refresh_: # Нужно синхронизировать try: # Удалить все из дерева tree_prj = self.getParent() tree_prj.DeleteAllItems() # Построить дерево узлов по ресурсному файлу self.prj_res_manager.openPrj(prj_file) self._openDefault() # Создание ресурсов for cur_res in self.prj_res_manager.getPrjRoot(): self.buildPrjRes(self.getResources(), cur_res.values()[0], cur_res.keys()[0]) # Создание дерева функционала self.getModules().buildPrjPy(os.path.dirname(prj_file)) # Создание дерева импортируемых систем self.getImpSystems().buildSubSystemsTree( self.prj_res_manager.getImportSystems()) # Установить в дереве корень tree_prj.setRoot(self) # Сохранить время и размер до следующей синхронизации self.prj_res_time = cur_prj_res_time self.prj_res_size = cur_prj_res_size except: log.error(u'Synhronization tree/file project error: <%s>' % self.name)
def outErr(msg=u'', TxtCP_=IC_TXT_CODEPAGE, DevCP_=IC_CONSOLE_CODEPAGE, Device_=IC_CONSOLE_ERR): """ Выдает сообщение о последней ошибке в регистратор (эту функцию можно использовать только в блоке exception). @param msg: Текст сообщения. @param TxtCP_: Кодовая страница текста сообщения. @param DevCP_: Кодовая страница вывода на устройство. @param Device_: Указание устройства вывода. """ txt = u'' if msg: txt = ReCodeString(msg, TxtCP_, DevCP_) if Device_ == IC_LOG: log.error(txt) return True elif Device_ == IC_LOG_CONSOLE: log.error(txt) Device_ = IC_CONSOLE return outLastErr(txt, Device_)
def auto_replace(sTxt, dReplaces=None): """ Запуск автозамен из контекста. @param sTxt: Редактируемый текст. @param dReplaces: Словарь замен, если None, то берется locals(). @return: Возвращается отредактированный текст или None в случае возникновения ошибки. """ if dReplaces is None: dReplaces = locals() if sTxt and (dReplaces is not None): replace_places = re.findall(VAR_PATTERN, sTxt) replaces = dict([(place, dReplaces.get(_getVarName(place), FIND_REPLACEMENT_ERR)) for place in replace_places]) for place, value in replaces.items(): place = ic_str.toUnicode(place, DEFAULT_ENCODING) value = ic_str.toUnicode(value, DEFAULT_ENCODING) try: log.debug(u'Автозамена %s -> <%s>' % (place, value)) except UnicodeEncodeError: log.error(u'Ошибка отображения автозамены %s' % place) except UnicodeDecodeError: log.error(u'Ошибка отображения автозамены %s' % place) sTxt = sTxt.replace(place, value) return sTxt elif sTxt is None: log.warning(u'Не определен текст для автозамен') elif dReplaces is None: log.warning(u'Не определены замены для автозамен') return None
import ic.engine.ic_user as ic_user import ic.utils.ic_mode as ic_mode from . import PrjRes from . import menuRootNode from . import ImpNode from . import prj_env from . import prj_report from . import prj_security from . import prj_resource from . import prj_module try: import winpdb except: log.error(u'Winpdb import Error') import shlex import subprocess _ = wx.GetTranslation __version__ = (0, 0, 2, 2) # Константы # Файл журнала зарегистрированных пользователей PRJ_REG_JRN_FILE_NAME = './log/prj_reg_user_journal.ini' class PrjRoot(ImpNode.PrjImportSys): """
""" import os import os.path import shutil import re try: from . import log except Exception: from ic.log import log try: import configparser except ImportError: log.error('Ошибка импорта configparser', bForcePrint=True) __version__ = (0, 1, 1, 1) CFG_FILE_EXT = '.cfg' INI_FILE_EXT = '.ini' DEFAULT_ENCODE = 'utf-8' def loadParamCFG(sCFGFileName, sParamName): """ Чтение параметра из файла настроек. @type sCFGFileName: C{string} @param sCFGFileName: Полное имя файла настроек. @type sParamName: C{string} @param sParamName: Имя параметра.