diff --git a/.gitignore b/.gitignore index b315aa5..d536aaa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /__pycache__/ /dist/ /build/ -/*/__pycache__ +/*/__pycache__/ +/data/output/ *.log \ No newline at end of file diff --git a/README.md b/README.md index 33f5436..c8c7b59 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ -HANDHELD 接收及数据处理程序 +# 手持式桌面数据处理 +数据处理不需要ID, 默认值为100 -分支:server desktop \ No newline at end of file +# 数据目录格式 +info 和sensor文件分别在不同目录,对应的文件名一样 +data/2023_01/11/info +data/2023_01/11/sensor + +# 输出目录 +data/output + +格式 + +信息 +抬头 +数据(时间--值) \ No newline at end of file diff --git a/Ramses.py b/Ramses.py new file mode 100644 index 0000000..0051473 --- /dev/null +++ b/Ramses.py @@ -0,0 +1,187 @@ +#! python3 +# -*- encoding: utf-8 -*- +''' +@File : Ramses.py +@Time : 2023/03/03 11:09:50 +@Author : Jim @ Yiwin +@Version : 1.0 +@Contact : jim@yi-win.com +@Desc : +@para : 23 ..07 .... 06 05 04 03 02 01 00 + ip信息不包含 +''' + +import struct +import numpy as np +from pathlib import Path +from tools.mylogger import log +from myconfig import RamsesAWRAMS, RamsesSURFACE, RamsesPROFILE, DeviceType + + +class Ramses(object): + + def __init__(self,): + """ + @description :处理Ramses的数据标定 Hex -- realWavelength Intensity + @param : 23 ..07 .... 06 05 04 03 02 01 00 + ip信息不包含 + @Returns : realWavelength Intensity + """ + self.buf = b'' + self.it = None + self.light_int = None # 未标定的整数值 + self.spectrum = None # 光谱强度 + # self.current_buf = "" + # self.current_buf_seq = 0 + # self.current_it_int = {"it": 0, "light_int": []} # 积分时间及换算的整数值 + # self.res = {"wavelength": [], "light": []} + self.cal_cfg = {} + # self.current_cal = {} # 当前传感器的序列号 + pass + + def setBuf(self, buf: bytes): + self.buf = buf + pass + + def setCalCfg(self, d: dict): + self.cal_cfg = d + pass + + def getRealWavelength(self, d: dict): + self.cal_cfg = d + pass + + def getSpectrum(self): + return self.spectrum + + def resetPara(self, ): + self.buf = b'' + self.it = None + self.light_int = None + self.spectrum = None # 光谱强度 + self.cal_cfg = {} + pass + + def resetItSpectrum(self, ): + self.it = None + self.spectrum = None # 光谱强度 + pass + + def printPara(self, ): + print(f"**************Ramses printPara*******************") + print(f"{self.buf}") + print(f"{self.cal_cfg}") + print(f"{self.it}") + print(f"{self.light_int}") + print(f"{self.spectrum}") + print(f"**************Ramses printPara*******************") + pass + + def dealBuf(self, ip_included:bool=False): + """多个传感器的数据处理, 头部是否包含Ip帧的信息""" + log.info(f" dealBuf ", __name__) + + res = {} + len_ = len(self.buf) + if len_ < 576: + return + if ip_included: + self.buf = self.buf[26:] + len_ = len_ - 26 + if len_ % 576 != 0: + return + + for i in range(int(len_/576)): + res.update({i+1: {}}) + temp_buf = self.buf[7:71] + self.buf[79:143] + \ + self.buf[151:215] + self.buf[223:287] + \ + self.buf[295:359] + self.buf[367:431] + \ + self.buf[439:503] + self.buf[511:575] + self.ConvertAndCalibrate( temp_buf ) + # print(len(temp_buf)) + temp = self.__ConvertBytesToInt(temp_buf) + res.update( { i+1: temp } ) + # print(res) + pass + + def ConvertAndCalibrate(self,) -> None: + log.debug(f" ConvertAndCalibrate ", __name__) + temp = self.__ConvertBytesToInt( ) + self.__CalibrateSpectrumData( ) + pass + + # 转换一个传感器的部分 + def __ConvertBytesToInt(self ) -> None: + res = {} + d = [] # List [ Tuple[ it:int, sing_set:tuple[int] ] ] + self.it = 2 << int(self.buf[1]) # integrated time + self.light_int = struct.unpack( + " None: + log.info(f"ConfigAWRAMS init: ", __name__, "", "") + self.device_type = None + self.configuration =None + self.cal_configuration = {} + pass + + + + def setDeviceType(self, device_type:str) -> None: + self.device_type = device_type.lower() + pass + + def setSystemCfgDict(self, cfg:dict) -> None: + self.configuration = cfg + log.info(f"self.configuration : {self.configuration} ", __name__, "", "") + pass + + def getCalConfiguration(self) -> None: + if self.device_type == None: + self.cal_configuration = None + if self.configuration == None: + self.cal_configuration =None + + for k,v in self.configuration.items(): + + if v["SN"] == "" or v['FUNC']=="": + pass + else: + self.cal_configuration.update( {v["FUNC"]:{}} ) + self.cal_configuration[v["FUNC"]].update( {"SN":v['SN']} ) + self.cal_configuration[v["FUNC"]].update( {"FUNC":v['FUNC']} ) + + self.__init_configuration_basic() + self.__init_configuration_cal() + self.__init_configuration_IP_SAM() + pass + + def __init_configuration_basic(self ) -> None: + # self.cfgtool = Config() + for k in self.cal_configuration.keys(): + sn = self.cal_configuration[k]["SN"] + if self.__isSamIniExisted(sn): + self.cal_configuration[k].update({ "TYPE" : "SAM" }) + self.cal_configuration[k].update({ "samsn" : sn }) + self.cal_configuration[k].update({ "inifile" : "SAM_"+sn+".ini" }) + self.cal_configuration[k].update({ "calfile" : "Cal_SAM_"+sn+".dat" }) + self.cal_configuration[k].update({ "calaqfile" : "CalAQ_SAM_"+sn+".dat" }) + self.cal_configuration[k].update({ "backfile" : "Back_SAM_"+sn+".dat" }) + if self.__isSamIPIniExisted(sn): + self.cal_configuration[k].update({ "TYPE" : "SAMIP" }) + samsn = self.__getSAMSN(sn) + if samsn== None: + log.warning(f"Cannot get samsn from Sensor: {sn}", __name__, "", "" ) + raise Exception(f"Cannot get samsn from Sensor: {sn}") + self.cal_configuration[k].update({ "samsn" : samsn }) + self.cal_configuration[k].update({ "inifile" : "SAMIP_"+sn+"_ALL.ini" }) + self.cal_configuration[k].update({ "calfile" : "Cal_SAM_"+samsn+".dat" }) + self.cal_configuration[k].update({ "calaqfile" : "CalAQ_SAM_"+samsn+".dat" }) + self.cal_configuration[k].update({ "backfile" : "Back_SAM_"+samsn+".dat" }) + if not self.__isSamIniExisted(sn) and not self.__isSamIPIniExisted(sn): + log.warning(f"Cannot find ini file for Sensor: {sn}", __name__, "", "" ) + raise Exception(f"Cannot find ini file for Sensor: {sn}") + + pass + + def __init_configuration_cal(self ) -> None: + # self.cfgtool = Config() + for k in self.cal_configuration.keys(): + sn = self.cal_configuration[k]["SN"] + # Device File + calpath = CAL_DIR.joinpath(self.device_type, self.cal_configuration[k]["calfile"]) + if calpath.exists( ): + res = ReadCal.read_columns_set_by_mark( calpath, FILE_MARK, 1 ) + self.cal_configuration[k].update({ "cal" : res[1][0] }) + calaqpath = CAL_DIR.joinpath(self.device_type, self.cal_configuration[k]["calaqfile"]) + if calaqpath.exists( ): + res = ReadCal.read_columns_set_by_mark( calaqpath, FILE_MARK, 1 ) + self.cal_configuration[k].update({ "calaq" : res[1][0] }) + backpath = CAL_DIR.joinpath(self.device_type, self.cal_configuration[k]["backfile"]) + if calaqpath.exists( ): + res = ReadCal.read_columns_set_by_mark( backpath, FILE_MARK, 1,2 ) + self.cal_configuration[k].update({ "b0" : res[1][0] }) + self.cal_configuration[k].update({ "b1" : res[1][1] }) + pass + + + + def __init_configuration_IP_SAM(self ) -> None: + # self.cfgtool = Config() + for j in self.cal_configuration.keys(): + # log.debug(f"__init_configuration_IP_SAM {j}", __name__, "", "" ) + inipath = CAL_DIR.joinpath(self.device_type, self.cal_configuration[j]["inifile"]) + # log.debug(f"__init_configuration_IP_SAM {inipath}", __name__, "", "" ) + sam = ReadCal.readSAMCalFromIni(inipath) + # log.debug(f"__init_configuration_IP_SAM {sam}", __name__, "", "" ) + for k,v in sam.items(): + self.cal_configuration[j].update({ k : v }) + if self.cal_configuration[j]["TYPE"] == "SAMIP": + ip = ReadCal.readIPCalFromIni(inipath) + for k,v in ip.items(): + self.cal_configuration[j].update({ k : v }) + + def __isSamIniExisted(self,sn) ->bool: + sn_0 = "SAM_"+str(sn)+".ini" + path_ = CAL_DIR.joinpath(self.device_type.lower(), sn_0) + if path_.exists(): + return True + return False + + + def __isSamIPIniExisted(self,sn) ->bool: + sn_0 = "SAMIP_"+str(sn)+"_ALL.ini" + path_ = CAL_DIR.joinpath(self.device_type.lower(), sn_0) + if path_.exists(): + return True + return False + + def __getSAMSN(self,sn) -> None: + sn_0 = "SAMIP_"+str(sn)+"_ALL.ini" + path_ = CAL_DIR.joinpath(self.device_type.lower(), sn_0) + # path_ = DATA_DIR.joinpath(self.device.lower(), CAL_DIR, sn_0) + samsn = ReadCal.readSamSNFromIni( path_ ) + if samsn == None: + return None + return samsn + pass + + # def __init2__(self, device:str, **kwargs) -> None: + # """ + # get cal parameter for every sensor + # para : {"1":{"SN":"85B5","FUNC","Lsky"},"2":{},"3":{}} + # """ + # # log.info(f"ProcessAWRAMS kwargs: {kwargs}", __name__, "", "") + # # log.info(f"len: { len(kwargs)}", __name__, "", "") + + # if len(kwargs) != 3: + # log.warning(f" pass a wrong para to ProcessAWRAMS {kwargs}", __name__, "", "") + # self.device = device.lower() # surface profile awrams + # self.ramses = {} + + # # 生成标定文件 { } + # for k,v in kwargs.items(): + # self.ramses.update( {v["FUNC"]:{}} ) + # self.ramses[v["FUNC"]].update( {"SN":v['SN']} ) + # self.ramses[v["FUNC"]].update( {"FUNC":v['FUNC']} ) + # pass + # log.debug(f" ===== {self.ramses}",__name__, "", "" ) + + + # # if kwargs.__contains__("1"): + # # self.ramses.append( self.cfgtool.getDictByAttr("ramses")) + # # self.cfgtool.set_attr(self.ramses[1],kwargs['1']"SN",kwargs['1']) + # # if kwargs.__contains__("2"): + # # self.ramses.append( self.cfgtool.getDictByAttr("ramses")) + # # self.cfgtool.set_attr(self.ramses[2],"SN",kwargs['1']) + # # if kwargs.__contains__("3"): + # # self.ramses.append( self.cfgtool.getDictByAttr("ramses")) + # # self.cfgtool.set_attr(self.ramses[3],"SN",kwargs['1']) + + # self.__init_configuration_basic() + # self.__init_configuration_cal() + # self.__init_configuration_IP_SAM() + + # # log.info(f"ProcessAWRAMS after initiate: {kwargs}", __name__, "", "") + + # def __init_configuration_basic2(self ) -> None: + # # self.cfgtool = Config() + # for k in self.ramses.keys(): + # sn = self.ramses[k]["SN"] + # if self.__isSamIniExisted(sn): + # self.ramses[k].update({ "TYPE" : "SAM" }) + # self.ramses[k].update({ "samsn" : sn }) + # self.ramses[k].update({ "inifile" : "SAM_"+sn+".ini" }) + # self.ramses[k].update({ "calfile" : "Cal_SAM_"+sn+".dat" }) + # self.ramses[k].update({ "calaqfile" : "CalAQ_SAM_"+sn+".dat" }) + # self.ramses[k].update({ "backfile" : "Back_SAM_"+sn+".dat" }) + # if self.__isSamIPIniExisted(sn): + # self.ramses[k].update({ "TYPE" : "SAMIP" }) + # samsn = self.__getSAMSN(sn) + # if samsn== None: + # log.warning(f"Cannot get samsn from Sensor: {sn}", __name__, "", "" ) + # raise Exception(f"Cannot get samsn from Sensor: {sn}") + # self.ramses[k].update({ "samsn" : samsn }) + # self.ramses[k].update({ "inifile" : "SAMIP_"+sn+"_ALL.ini" }) + # self.ramses[k].update({ "calfile" : "Cal_SAM_"+samsn+".dat" }) + # self.ramses[k].update({ "calaqfile" : "CalAQ_SAM_"+samsn+".dat" }) + # self.ramses[k].update({ "backfile" : "Back_SAM_"+samsn+".dat" }) + # if not self.__isSamIniExisted(sn) and not self.__isSamIPIniExisted(sn): + # log.warning(f"Cannot find ini file for Sensor: {sn}", __name__, "", "" ) + # raise Exception(f"Cannot find ini file for Sensor: {sn}") + + # pass + + # def __init_configuration_cal2(self ) -> None: + # # self.cfgtool = Config() + # for k in self.ramses.keys(): + # sn = self.ramses[k]["SN"] + # # Device File + # calpath = CAL_DIR.joinpath(self.device, self.ramses[k]["calfile"]) + # if calpath.exists( ): + # res = Readfile.read_columns_set_by_mark( calpath, FILE_MARK, 1 ) + # self.ramses[k].update({ "cal" : res[1][0] }) + # calaqpath = CAL_DIR.joinpath(self.device, self.ramses[k]["calaqfile"]) + # if calaqpath.exists( ): + # res = Readfile.read_columns_set_by_mark( calaqpath, FILE_MARK, 1 ) + # self.ramses[k].update({ "calaq" : res[1][0] }) + # backpath = CAL_DIR.joinpath(self.device, self.ramses[k]["backfile"]) + # if calaqpath.exists( ): + # res = Readfile.read_columns_set_by_mark( backpath, FILE_MARK, 1,2 ) + # self.ramses[k].update({ "b0" : res[1][0] }) + # self.ramses[k].update({ "b1" : res[1][1] }) + # pass + + # def __init_configuration_IP_SAM2(self ) -> None: + # # self.cfgtool = Config() + # for j in self.ramses.keys(): + # # log.debug(f"__init_configuration_IP_SAM {j}", __name__, "", "" ) + # inipath = CAL_DIR.joinpath(self.device, self.ramses[j]["inifile"]) + # # log.debug(f"__init_configuration_IP_SAM {inipath}", __name__, "", "" ) + # sam = Readfile.readSAMCalFromIni(inipath) + # # log.debug(f"__init_configuration_IP_SAM {sam}", __name__, "", "" ) + # for k,v in sam.items(): + # self.ramses[j].update({ k : v }) + # if self.ramses[j]["TYPE"] == "SAMIP": + # ip = Readfile.readIPCalFromIni(inipath) + # for k,v in ip.items(): + # self.ramses[j].update({ k : v }) \ No newline at end of file diff --git a/data/2023_03/10/info/09_33_42 b/data/2023_03/10/info/09_33_42 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/10/info/09_33_55 b/data/2023_03/10/info/09_33_55 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/10/sensor/09_33_42 b/data/2023_03/10/sensor/09_33_42 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/10/sensor/09_33_55 b/data/2023_03/10/sensor/09_33_55 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/info/16_32_03 b/data/2023_03/17/info/16_32_03 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/info/16_32_19 b/data/2023_03/17/info/16_32_19 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/info/17_31_45 b/data/2023_03/17/info/17_31_45 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/info/17_34_55 b/data/2023_03/17/info/17_34_55 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/sensor/16_32_03 b/data/2023_03/17/sensor/16_32_03 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/17/sensor/16_32_19 b/data/2023_03/17/sensor/16_32_19 new file mode 100644 index 0000000..e69de29 diff --git a/data/2023_03/20/info/14_49_15 b/data/2023_03/20/info/14_49_15 new file mode 100644 index 0000000..fae6f46 Binary files /dev/null and b/data/2023_03/20/info/14_49_15 differ diff --git a/data/2023_03/20/info/14_49_53 b/data/2023_03/20/info/14_49_53 new file mode 100644 index 0000000..aff7373 Binary files /dev/null and b/data/2023_03/20/info/14_49_53 differ diff --git a/data/2023_03/20/sensor/14_49_15 b/data/2023_03/20/sensor/14_49_15 new file mode 100644 index 0000000..84c1b09 Binary files /dev/null and b/data/2023_03/20/sensor/14_49_15 differ diff --git a/data/2023_03/20/sensor/14_49_53 b/data/2023_03/20/sensor/14_49_53 new file mode 100644 index 0000000..ebe3e50 Binary files /dev/null and b/data/2023_03/20/sensor/14_49_53 differ diff --git a/handheld.py b/handheld.py new file mode 100644 index 0000000..e03cbdd --- /dev/null +++ b/handheld.py @@ -0,0 +1,906 @@ +#! python3 +# -*- encoding: utf-8 -*- +''' +@File : handheld.py +@Time : 2023/02/24 17:20:59 +@Author : Jim @ Yiwin +@Version : 1.0 +@Contact : jim@yi-win.com +''' + +CUR_TIME_STR_FMT = "%Y-%m-%d %H:%M:%S" + +import time +import locale +import struct +import numpy as np +from pathlib import PurePath,Path +from myconfig import CURRENT_DIR,DATA_DIR,OUTPUT_DIR,NEWLINE,ROWFACTOR,SAVE_EXT_NAME,TOKEN +from myconfig import DeviceType,RamsesSURFACE,RamsesAWRAMS,RamsesPROFILE +from tools.mylogger import log +from tools.myexception import MyException +from tools.mytime import MyTime +from tools.mypath import MyDir +from Ramses import Ramses + + + +class HandHeldBuf: + def __init__(self,) -> None: + self.__buf = b'' + self.__head = {} + self.__begin_sign = b'\x23' + self.__end_sign = b'\x0D' + self.data_ip = b'' + self.measure_group = { + "Lsky": b'', + "Esky": b'', + "Lwater": b'', + } + self.one_group_data= b'' + self.state = 0 + + def readFile2Buf(self, fpath) -> None: + with open(fpath,"rb") as f: + self.__buf = f.read() + pass + pass + + def read_buf(self, size: int) -> bytes: + if size > self.__buf.__len__(): + return b'' + ret = self.__buf[0:size] + self.__buf = self.__buf[size:] + return ret + + def write_buf(self, buf: bytes) -> None: + id = self.id + len = buf.__len__() + # logging.info(f'Received ID:{id} Size:{len}') + self.__buf = self.__buf+buf + + def get_buf_size(self) -> int: + return self.__buf.__len__() + + def back_bytes(self, buf: bytes) -> None: + self.__buf = buf+self.__buf + + def reset_head(self) -> None: + self.__head = {} + + def reset_buf(self) -> None: + self.__buf = b'' + + def getResult(self) -> str: + return self.res + + def resetMeasureGroup(self) -> None: + self.measure_group['Lsky'] = b'' + self.measure_group['Esky'] = b'' + self.measure_group['Lwater'] = b'' + + def getMeasureGroup(self) -> dict: + return self.measure_group + + def decode_handheld(self) -> bool: + '''以26个字节开始,一般26个00 ,然后23... 07.... ''' + if self.get_buf_size() < 1754: + self.__buf = b'' + return False + + self.data_ip = self.read_buf(26) + Lsky = self.read_buf(576) + Esky = self.read_buf(576) + Lwater = self.read_buf(576) + + self.measure_group['Lsky'] = self.deal_576_to_512(Lsky) + self.measure_group['Esky'] = self.deal_576_to_512(Esky) + self.measure_group['Lwater'] = self.deal_576_to_512(Lwater) + + if self.measure_group['Lsky'] == b'' \ + or self.measure_group['Esky'] == b'' \ + or self.measure_group['Lwater'] == b'' : + return False + + return True + + def decode_one_group_handheld(self) -> bool: + '''以26个字节开始,一般26个00 ,然后23... 07.... ''' + if self.get_buf_size() < 1754: + self.__buf = b'' + return False + + self.data_ip = self.read_buf(26) + self.one_group_data = self.read_buf(1728) + + return True + + def deal_576_to_512(self,data:bytes) -> bytes: + ''' 576字节校验,拆分成字典 23... 07.... ,然后254*2''' + ret = {} + index = 72 + for i in range(8): + temp = data[i*index : i*index+index] + # print( temp.hex()) + if temp[0] != 35 and temp[0]<8 and temp>0 : + return b'' + pass + ret.update( { temp[4]: temp} ) + if len(ret) != 8: + return b'' + ret_byte = ret[7][7:71]+ ret[6][7:71]+ ret[5][7:71]+ ret[4][7:71] \ + + ret[3][7:71]+ ret[2][7:71]+ ret[1][7:71]+ ret[0][7:71] + return ret_byte + + + def decode(self) -> str: + ret = '' + temp_buf = b'' + token = ";" + if TOKEN: + token = TOKEN + + if self.state == 0: + while self.get_buf_size() >= 1: + if self.read_buf(1) != self.__end_sign: + continue + self.state = 1 + break + + if self.state == 1: + while self.get_buf_size() >= 1: + buf = self.read_buf(1) + if buf != self.__end_sign: + temp_buf += buf + if buf == self.__end_sign: + ret = temp_buf[0:20].decode( + 'utf-8').strip(" ") + token + temp_buf[-9:-1].decode('utf-8').strip(" ") + log.info(f"decode : {ret}") + temp_buf = b'' + self.back_bytes(temp_buf) # 写回临时buf到 + self.res = ret + return ret + pass + + +class HandHeldPath(object): + '''处理一次测量''' + def __init__(self, ): + self.mode = 0 + self.cfg ={} + self.mydir = MyDir() + self.base_path:Path = Path() + self.output_path:Path = Path() + self.data_path:Path = Path() + self.filelist = [] + self.error_result = [] + pass + + def setMode( self, mode:int = 0 ): + self.mode = mode + pass + + def setBasePath( self, fpath:Path ): + self.base_path = fpath + pass + + def setDataPath( self, fpath:Path ): + self.data_path = fpath + pass + + def setOutputPath( self, fpath:Path ): + self.output_path = fpath + pass + + def getSensorPathFromInfoPath( self, info_path:Path, ) -> Path: + # 服务器上转移后的模式 + if self.mode == 1: + sensor_path = self.base_path.joinpath( + info_path.parent, + "sensor.bin" + ) + elif self.mode == 0: + sensor_path = self.base_path.joinpath( + "data", + info_path.parts[1][:4] + "_" + info_path.parts[1][-2:], + info_path.parts[2], + "sensor", + info_path.name + ) + else: + sensor_path = None + return sensor_path + pass + + def getOutputPathFromSensorPath(self,sensor_path:Path ) -> Path: + if self.mode == 1: + output_path = self.output_path.joinpath( + self.info_dict['year'] + "_" + self.info_dict['month'] + + "_" + self.info_dict['day'] + "_" + self.info_dict['hour'] + + "_" + self.info_dict['minute'] + "_" + self.info_dict['second'] + ) + elif self.mode == 0: + output_path = self.output_path.joinpath( + sensor_path.parts[1][:4] + "_" + sensor_path.parts[1][-2:] + + "_" +sensor_path.parts[2] + "_" +sensor_path.name + ) + else: + output_path = None + return output_path + pass + + def getCurrentMeasureTimeFromPath(self,fpath:Path ) -> str: + ret = '' + if self.mode == 1: # 读信息txt获得时间 + txt_path = fpath.parent.glob("*.txt") + txt_stem = txt_path[0].stem + ret = fpath.parts[1][:4]+"-"+fpath.parts[1][-2:]+"-"+fpath.parts[2]+" " \ + + txt_stem[-9:-7] + ":" + txt_stem[-6:-4] + ":" + txt_stem[-3:-1] + pass + elif self.mode == 0: + ret = fpath.parts[1][:4]+"-"+fpath.parts[1][-2:]+"-"+fpath.parts[2]+" " \ + + fpath.name[0:2] + ":" + fpath.name[3:5] + ":" + fpath.name[6:8] + else: + pass + return ret + pass + + def getDataFileList(self, ): + ''' + 获得成对的info sensor 文件 + [目录名,文件名,年月日,时间, measure_id] + ''' + # ret = [] + fs = None + self.filelist = [] + if self.mode == 1: + fs = self.data_path.glob( "*/*/*/*/info.bin" ) + else: + fs = self.data_path.glob( "*/*/info/*" ) + + for f in fs: + error_file = {} + if f.stat().st_size==0: + error_file.update( {"path": f } ) + error_file.update( {"error":"info file size is zero"} ) + self.error_result.append(error_file) + continue + + # self.info_path_fname = f + sensor_path = self.getSensorPathFromInfoPath(f) + # sensor_path = Path(sensor_purepath) + # sensor 文件不存在 + if not sensor_path.exists(): + error_file.update( {"path":f} ) + error_file.update( {"error":"cannot find the sensor file "} ) + self.error_result.append(error_file) + continue + + # sensor文件大小为0 + if sensor_path.stat().st_size==0: + error_file.update( {"path":sensor_path} ) + error_file.update( {"error":"sensor file size of the sensor is zero' "} ) + self.error_result.append(error_file) + continue + self.setFilelist(f,sensor_path ) + pass + + # def getDataFileList_SD(self, mode:int = 0 ): + # ''' + # 获得成对的info sensor 文件 + # [目录名,文件名,年月日,时间] + # ''' + # # ret = [] + # fs = self.data_path.glob( "*/*/info/*" ) + # for f in fs: + # error_file = {} + # if f.stat().st_size==0: + # error_file.update( {"path": f.name } ) + # error_file.update( {"error":"info file size is zero"} ) + # self.error_result.append(error_file) + # continue + # self.info_path_fname = f + # sensor_path = self.getSensorPathFromInfoPath( f ) + # # sensor_path = Path(sensor_purepath) + # # sensor 文件不存在 + # if not sensor_path.exists(): + # error_file.update( { "path" : f } ) + # error_file.update( {"error":"cannot find the sensor file "} ) + # self.error_result.append(error_file) + # continue + + # # sensor文件大小为0 + # if sensor_path.stat().st_size==0: + # error_file.update( { "path" : f } ) + # error_file.update( {"error" : "the file size of the sensor is zero' "} ) + # self.error_result.append(error_file) + # continue + + # self.setFilelist(f,sensor_path,mode=mode) + # # print(self.filelist) + # pass + + def setFilelist(self, info_path:Path, sensor_path:Path): + temp = {} + temp.update( {"info_path" : info_path } ) + temp.update( {"name" : info_path.name} ) + temp.update( {"parent" : info_path.parent} ) + + if self.mode==1: # 服务器转移后目录 + temp.update( {"year" : info_path.parts[-5] } ) + temp.update( {"month" :info_path.parts[-4] } ) + temp.update( {"day" :info_path.parts[-3] } ) + + temp.update( {"year" : info_path.parts[1][:4] } ) + temp.update( {"month" :info_path.parts[1][-2:] } ) + temp.update( {"day" :info_path.parts[2] } ) + temp.update( { "sensor_path" :sensor_path } ) + self.filelist.append(temp) + + def getFilelist(self, ): + return self.filelist + + def printTest(self,d,sleep_time:int=5): + log.info( f"***** : I am testing from HandheldPath ********", __name__ ) + print(d) + log.info( f"***** : Ending testing from HandheldPath ********", __name__ ) + time.sleep(sleep_time) + pass + +class HandHeld(object): + def __init__(self, ): + """ + @description : 手持数据初始化 + """ + self.device_type = DeviceType.SURFACE.name + self.device_enum = None + self.device_id = {} + self.syscfg = {} + self.retrieve ={} + self.error_result=[] + self.mode = 0 # 0:默认SD数据, 1:服务器数据 + self.base_path = CURRENT_DIR + self.current_path = CURRENT_DIR + self.data_path = DATA_DIR + self.output_path = OUTPUT_DIR + self.info_path_fname:Path = self.base_path + self.sensor_path_fname:Path = self.base_path + self.filelist = [] # 包含了全部路径信息 + self.intensity_before_avg = None + self.intensity_after_avg = {} # 最终结果{lsky: esky: lwater: } + self.intensity_after_interpo = {} # 最终结果{lsky: esky: lwater: } + + self.one_group_result = {} # 手持式 多次间隔 + self.wavelength = np.array([]) + self.real_wavelength = {} # 最终结果{lsky: esky: lwater: } + self.current_filepath = '' # 不含后缀 + self.current_measure_time = None # 当前测量时间 + self.current_group_num = 0 + self.measurement_interval = 0 + self.measurement_repeat = 1 + # self.sl2f = SaveList2File() + self.mydir = MyDir() + self.my_time = MyTime() + self.hhb = HandHeldBuf() + self.hhp = HandHeldPath() + self.ramses = Ramses() + self.info_dict = {} + self.res = {} # 最终结果{lsky: esky: lwater: Lw: Rs:} + + # 方法 + self.setDeviceEnum() + self.setMode() + self.set_hhp_path() + pass + + def setMode(self,mode=0 ): + self.hhp.setMode (mode) # 0 :读SD卡 1:读服务器数据 + + def set_hhp_path(self, ): + self.hhp.setBasePath (self.base_path) + self.hhp.setDataPath (self.data_path) + self.hhp.setOutputPath (self.output_path) + + def setDeviceEnum(self, ): + if self.device_type == DeviceType.SURFACE.name: + self.device_enum = RamsesSURFACE + if self.device_type == DeviceType.AWRAMS.name: + self.device_enum = RamsesAWRAMS + if self.device_type == DeviceType.PROFILE.name: + self.device_enum = RamsesPROFILE + + def getDataFileList(self, ): + self.hhp.getDataFileList() + self.filelist = self.hhp.getFilelist() + # self.printTest(self.filelist) + pass + + def resetCurrentTime(self, num): + if self.current_measure_time == "": + return None + self.my_time.setCurrentTimeStr(self.current_measure_time) + self.my_time.timeDelta( seconds= self.measurement_interval * num) + self.current_measure_time = self.my_time.cur_time_str + pass + + def dealAllMeasurements(self, ): + log.info(f" 所有测量文件", __name__, "dealAllMeasurements", ) + if len(self.filelist)<1: + pass + # 前面已经考虑各种文件错误 + for df in self.filelist: + # 处理信息帧 + self.info_dict = {} + self.info_path_fname:Path = df["info_path"] + self.sensor_path_fname:Path = df["sensor_path"] + hex_info = self.read_bin( self.info_path_fname ) + try: + self.info_dict = self.decode_info( hex_info ) + except: + log.error( f"处理信息文件" + + "/" +self.info_path_fname.stem + + "出现错误", __name__, "dealAllMeasurements" ) + raise MyException( "处理文件"+ self.info_path_fname + "出现错误") + pass + + try: + # self.dealOneMeasurement(self.sensor_path_fname ) + self.measurement_interval = int(self.info_dict['Measure_Interval']) + self.measurement_repeat = int(self.info_dict['Measure_Repeat']) + self.dealOneHandheldMeasurement(self.sensor_path_fname ) + except Exception as e: + log.error( "处理传感器文件" + self.sensor_path_fname.name + "出现错误",__name__,"dealAllMeasurements") + raise MyException( "处理传感器文件" + self.sensor_path_fname.name + "出现错误" ) + pass + log.info(f"Finished !! ", __name__, "dealAllMeasurements") + return True,self.error_result + pass + + def dealOneHandheldMeasurement(self, fpath:Path): + '''handheld一次测量包含多组数据''' + # 调用handheldbuf 处理,将一组数据提交出来 + log.info(f" 手持一个文件,多组测量数据", __name__, "dealOneHandheldMeasurement") + if len(self.filelist)<1: + pass + + # 当前文件名 + self.output_path = OUTPUT_DIR + self.current_filepath = fpath + self.current_measure_time = self.hhp.getCurrentMeasureTimeFromPath(fpath) + self.ymdhms = "20"+ str(self.info_dict['year']) + '_' \ + + str(self.info_dict['month']) + '_' \ + + str(self.info_dict['day']) + '_' \ + + str(self.info_dict['hour']) + '_' \ + + str(self.info_dict['minute']) + '_' \ + + str(self.info_dict['second']) + self.output_path = self.output_path.joinpath( self.ymdhms ) + log.debug(f"current_measure_time: {self.current_measure_time}", __name__, "dealOneHandheldMeasurement") + + self.hhb.readFile2Buf(fpath) + log.debug(f"buf: {self.hhb.get_buf_size()}", __name__, "dealOneHandheldMeasurement") + self.decode_sensor_buf() + + # 解析Buf, 对buf分组,获得[{lsky: esky : lwater} .... ] + len_total = len(self.intensity_before_avg) + if len_total%self.measurement_repeat != 0: + self.res = {} + return # 返回退出 + group_num = int(len_total/self.measurement_repeat) + + log.info(f"group_num -> {group_num}, ervery group -> {self.measurement_repeat} ", __name__, "dealOneHandheldMeasurement") + self.real_wavelength = self.getWavelenthDict() + if group_num == 1: + self.dealOneGroup() # self.intensity_before_avg + return + + self.dealMultiGroup(group_num) + + def dealMultiGroup(self, group_num:int ): + log.info(f"group_num: {group_num}", __name__, "dealMultiGroup") + # 分组进行处理 + for i in range(group_num): + self.current_group_num = i + # 重设当前测量时间 ????????? + locale.setlocale(locale.LC_ALL, '') + self.resetCurrentTime(self.current_group_num) + self.res = {} + tmp_before_avg = [] + for j in range( self.measurement_repeat ): + tmp_before_avg.append( self.intensity_before_avg[j+i*self.measurement_repeat] ) + pass + self.getAvg(tmp_before_avg) + self.__do_sensor_dict_interpo() + + self.appendSave() + # self.checkAndSaveData( ) + # self.getLwRsAndSave() + # path_info_txt = self.output_path.joinpath( "info.txt" ) + # self.save_dict_to_file( self.info_dict, path_info_txt ) + + def dealOneGroup(self, ): + # 分组,并获得平均值, 255个未插值结果 (依据 measurement_interval measurement_repeat) + self.output_path = OUTPUT_DIR + self.getAvg( self.intensity_before_avg ) + + # 插值 + self.real_wavelength = self.getWavelenthDict() + self.__do_sensor_dict_interpo() + + self.ymdhms = "20"+ str(self.info_dict['year']) + '_' \ + + str(self.info_dict['month']) + '_' \ + + str(self.info_dict['day']) + '_' \ + + str(self.info_dict['hour']) + '_' \ + + str(self.info_dict['minute']) + '_' \ + + str(self.info_dict['second']) + + self.output_path = self.output_path.joinpath( self.ymdhms ) + self.appendSave() + # self.checkAndSaveData( ) + # self.getLwRsAndSave() + # path_info_txt = self.output_path.joinpath( "info.txt" ) + # self.save_dict_to_file( self.info_dict, path_info_txt ) + + def dealOneMeasurement(self, fpath:Path): + '''handheld一次测量包含多组数据''' + # 调用handheldbuf 处理,将一组数据提交出来 + log.info(f"dealOneMeasurement: 一组测量数据", __name__, "dealOneMeasurement") + if len(self.filelist)<1: + pass + + # 当前文件名 + self.current_filepath = fpath + self.current_measure_time = self.hhp.getCurrentMeasureTimeFromPath(fpath) # ?? + self.hhb.readFile2Buf(fpath) + self.decode_sensor_buf() + self.real_wavelength = self.getWavelenthDict() + self.dealOneGroup() + + + def decode_sensor_buf(self,) : + # 处理Buf,对多组数据取平均 + self.intensity_before_avg = [] + # res_before_avg = [] + self.clearRes() # 清空数据 + while True: + if not self.hhb.decode_one_group_handheld() : + break # 清空数据 + + res = {} + buf = self.hhb.one_group_data[26:] + for i in range(1,4,1): + temp_buf = buf[7:71] + buf[79:143] + \ + buf[151:215] + buf[223:287] + \ + buf[295:359] + buf[367:431] + \ + buf[439:503] + buf[511:575] + + # Ramses类 标定处理,设置buf 标定文件 + self.ramses.setBuf(temp_buf) + func = self.getFuncBySeq(i) + cfg = self.getCfgByFunc( func) + self.ramses.setCalCfg(cfg) + self.ramses.resetItSpectrum() + self.ramses.ConvertAndCalibrate() + res.update({ func : self.ramses.spectrum }) + self.intensity_before_avg.append( res ) + pass + + def getAvg( self, d:list) : + log.info(f"getAvg: 平均多组数据", __name__, "getAvg") + data = d + ret = {} + len_result = len(data) + if len_result == 0: + self.intensity_after_avg ={} + return None + if len_result == 1: + self.intensity_after_avg = data[0] + return None + ret = data[0] + + res_dict = self.getRetDict() + + for k in res_dict.keys(): + for i in range(1,len_result,1): + data[0][k] = data[0][k] + data[i][k] + ret = data[0][k]/len_result + self.intensity_after_avg.update( { k : ret } ) + log.debug(f"getAvg: {self.intensity_after_avg}", __name__, "getAvg") + pass + + def getRetDict(self,) : + ret_dict = { } + ret_dict.update( {self.device_enum(1).name:np.array([])} ) + ret_dict.update( {self.device_enum(2).name:np.array([])} ) + ret_dict.update( {self.device_enum(3).name:np.array([])} ) + # self.one_group_result = ret_dict + return ret_dict + + def __do_sensor_dict_interpo(self,) : + log.info( f"同步处理多个个插值 ", __name__, "__do_sensor_dict_interpo" ) + self.clearRes() + for k in self.intensity_after_avg.keys(): + tmp = np.interp( self.wavelength, self.real_wavelength[k], self.intensity_after_avg[k] ) + self.res.update( { k : tmp } ) + + def getCfgByDid(self, func:str) : + cfg_id:dict = self.cfg.get(int(self.device_id)) + cfg_sensor = cfg_id.get( func) + return cfg_sensor + pass + + def getFuncBySeq(self, seq:int) : + func = "" + if self.device_type == DeviceType.AWRAMS.name: + func = RamsesAWRAMS(seq).name + if self.device_type == DeviceType.SURFACE.name: + func = RamsesAWRAMS(seq).name + if self.device_type == DeviceType.PROFILE.name: + func = RamsesAWRAMS(seq).name + return func + + def getCfgByFunc(self, func:str) : + cfg_id:dict = self.syscfg.get(int(self.device_id)) + cfg_sensor = cfg_id.get( func) + return cfg_sensor + pass + + def getCfgBySeq(self, seq:int) : + func = "" + if self.device_type == DeviceType.AWRAMS.name: + func = RamsesAWRAMS(seq).name + if self.device_type == DeviceType.SURFACE.name: + func = RamsesAWRAMS(seq).name + if self.device_type == DeviceType.PROFILE.name: + func = RamsesAWRAMS(seq).name + cfg_id:dict = self.syscfg.get(int(self.device_id)) + cfg_sensor = cfg_id.get( func) + return cfg_sensor + pass + + def appendSave(self, ) -> bool: + self.checkAndSaveData( ) + self.getLwRsAndSave() + path_info_txt = self.output_path.joinpath( "info.txt" ) + self.save_dict_to_file( self.info_dict, path_info_txt ) + + def checkAndSaveData(self, ) -> bool: + """ + check self.Lsky Esky Lwater and Save + 处理self.res 的数据 + """ + log.info(f"checkAndSaveData: {self.output_path.parts}", __name__) + self.mydir.setBaseDir(self.output_path) #基路径 + self.mydir.setHeader( self.wavelength.tolist(), TOKEN, "device_id_"+str(self.device_id) ) + # print(f"header_str : {self.mydir.header_str[-1:]}") + + if self.current_group_num == 0: # 当前组号为0 新建否则追加 + self.newFileByFunc( self.device_enum(1).name ) + self.newFileByFunc( self.device_enum(2).name ) + self.newFileByFunc( self.device_enum(3).name ) + pass + + self.appendFileByFunc( self.device_enum(1).name ) + self.appendFileByFunc( self.device_enum(2).name ) + self.appendFileByFunc( self.device_enum(3).name ) + + def newFileByFunc(self, func:str) -> None: + self.mydir.newFileIfNot( func+SAVE_EXT_NAME) + if self.mydir.checkHeader() == -1: + log.error(f"请备份文件:{self.mydir.current_filepath.parent} {self.mydir.current_filepath.name}, 并删除文件后再试!", __name__) + raise MyException( f"请备份文件:{self.mydir.current_filepath.parent} {self.mydir.current_filepath.name}, 并删除文件后再试!" ) + return False + if self.mydir.checkHeader() == 1: + pass + if self.mydir.checkHeader() == 0: + self.mydir.writeHeader() + pass + # 写入数据content + self.mydir.setContent(self.res[func].tolist(), TOKEN, self.current_measure_time) + self.mydir.writeContent() + + def appendFileByFunc(self, func:str) -> None: + # 追加写入数据content + self.mydir.setContent(self.res[func].tolist(), TOKEN, self.current_measure_time) + self.mydir.writeContent() + + def clearRes(self, ) -> None: + self.res = { } + + def getLwRsAndSave(self, ) -> bool: + """ + 并计算Lw Rs并保存 + """ + Lw = self.res["Lwater"] - ROWFACTOR * self.res["Lsky"] + self.res.update({ "Lw" : Lw }) + Rs = self.res["Lw"] / self.res["Esky"] + self.res.update({ "Rs" : Rs }) + self.mydir.setBaseDir(self.output_path) #基路径 + + # 保存 + + if self.current_group_num == 0: + self.newFileByFunc( "Lw" ) + self.newFileByFunc( "Rs" ) + pass + + self.appendFileByFunc( "Lw" ) + self.appendFileByFunc( "Rs" ) + + return True + + def read_bin(self,fpath: Path): + log.debug(f" readbin: ", __name__, "", "" ) + ret = None + if not fpath.exists() : + log.info(f"not find file: {fpath} ") + return ret + with open(fpath, 'rb') as file: + ret = file.read() + return ret + log.debug(f" readbin: {ret} ", __name__, "", "" ) + return ret + pass + + def decode_info( self,info: bytes ) -> dict: + ret = {} + # 剖面型加了1311+24个字节共26个字节 + # 保留字节有所变化,改为序列号,每个序列号两个字节 + try: + temp = struct.unpack(" None: + temp_str = "" + for key, value in info_dict.items(): + temp_str = temp_str + key + " : " + str(value) + "\n" + with open(fpath, "w+") as f: + f.write(temp_str) + + def save_error_to_file(self, errlist: list, fpath: Path) -> None: + temp_str = "" + if len(errlist) <1: + return None + for errdict in errlist: + temp_str = temp_str + errdict["path"] +" : "+ errdict["error"] + "\n" + pass + with open(fpath, "w+") as f: + f.write(temp_str) + return None + pass + + def getWavelenthDict( self, ) -> dict: + ret_dict = self.getRetDict() + cfg_id:dict = self.syscfg.get( int(self.device_id)) + for k in ret_dict.keys(): + tmp = self.getWavelength( cfg_id.get(k) ) + ret_dict.update({ k : tmp }) + return ret_dict + + def getWavelength(self,ramsesdict:dict) -> np.ndarray: + ret = [] + for i in range(1,256): + tmp = float(ramsesdict['c0s']) + float(ramsesdict['c1s'])*i \ + + float(ramsesdict['c2s'])*i*i + float(ramsesdict['c3s'])*i*i*i + ret.append(tmp) + pass + return np.array(ret) + + def setSyscfg(self, syscfg:dict): + self.syscfg = syscfg + + def setRetrieve(self, retrieve:dict): + log.debug( f"setRetrieve : {retrieve}......", __name__ ) + self.retrieve = retrieve + self.setNewWavelength() + # self.wavelength:np.ndarray = np.arange ( self.retrieve['beginWL'], self.retrieve['endWL'], self.retrieve['interval'] ) + + def setNewWavelength(self, ): + self.wavelength:np.ndarray = np.arange ( + self.retrieve['beginWL'], self.retrieve['endWL'], self.retrieve['interval'] ) + + def setDeviceID(self, did:int): + self.device_id = did + + def setDeviceType(self, device_type): + self.device_type = device_type + + def getErrorInfoDict(self, ): + return self.error_result + + def printResult(self,): + log.info( f"***** : Print Lsky Esky Lwater Lw Rs......", __name__ ) + print(self.res[self.device_enum(1)]) + print(self.res[self.device_enum(2)]) + print(self.res[self.device_enum(3)]) + print(self.res[self.device_enum(4)]) + print(self.res[self.device_enum(5)]) + pass + + def printTest(self,d,sleep_time:int=5): + log.info( f"***** : I am testing ********", __name__ ,"printTest") + print(d) + log.info( f"***** : Ending testing ********", __name__ ,"printTest") + time.sleep(sleep_time) + pass + +if __name__ == "__main__": + # hh = HandHeld() + # hh.getDataFileList() + # hh.dealAllMeasurements() + + # data/2023_02/07/sensor/14_02_46 + # hhb= HandHeldBuf() + # hhb.readFile2Buf("data/2023_02/07/sensor/14_02_46") + # hhb.decode_handheld() + # print(hh.error_result) + # print("======") + # print(hh.filelist) + + # print( hh.getDataFname() ) + + # t = b'\x07' + # print( int(t[0])) + # print( 2 << int(t[0])) + + + pass + diff --git a/listctrl.py b/listctrl.py new file mode 100644 index 0000000..210bc4f --- /dev/null +++ b/listctrl.py @@ -0,0 +1,32 @@ +from myconfig import TOKEN +import wx + +class Listctrl(wx.Panel): + ''' + # 需要在 Frame 实例化一个实例 + # 改变需要对实例化后的进行操作 + ''' + def __init__(self, parent ): + ''' + * panel 初始化后的样子 + ''' + # self.para_setting = para + super(Listctrl,self).__init__(parent) + self.locale = wx.Locale(wx.LANGUAGE_CHINESE_SIMPLIFIED) + + self.SetBackgroundColour('lightgrey') + + self.box = wx.BoxSizer(wx.HORIZONTAL) + + self.list_ctrl = wx.ListCtrl(self, -1, style = wx.LC_REPORT | wx.LC_SORT_DESCENDING) + self.list_ctrl.SetBackgroundColour( 'lightgrey' ) + + self.list_ctrl.InsertColumn(0, u'测量时间', width = 180) + self.list_ctrl.InsertColumn(1, u'花粉_Pollen', width = 180) + i = 1 + + self.list_ctrl.SetFont( wx.Font( 11, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False ) ) + + self.box.Add(self.list_ctrl,1,wx.EXPAND) + self.SetSizer(self.box) + self.Fit() diff --git a/myconfig.py b/myconfig.py new file mode 100644 index 0000000..b95ec06 --- /dev/null +++ b/myconfig.py @@ -0,0 +1,329 @@ +#! python3 +# -*- encoding: utf-8 -*- +''' +@File : myconfig.py +@Time : 2023/03/01 15:28:20 +@Author : Jim @ Yiwin +@Version : 1.0 +@Contact : jim@yi-win.com +@Descrip : SysConfig +''' + +import yaml +from enum import Enum +from pathlib import Path +VERSION = "3.3.5" +LASTDATE = "2023-03-09" +COMPANY = u"奕枫仪器" + +DEVICE_ID = [2] +CURRENT_DIR = Path() +DATA_DIR = Path("data") +CAL_DIR = Path("calfile") +OUTPUT_DIR = Path("data", "output") +YAML_FILE_NAME = "config.yml" +RETRIEVE_CFG_FILE = "retrieve.yml" +FILE_MARK = ['Spectrum', 'DATA'] +BEGIN_WAVELENGTH = 350 +END_WAVELENGTH = 950 +SAVE_EXT_NAME = ".csv" +INTERVAL = 1.0 +SEPARATOR = ";" +TOKEN = ";" +NEWLINE = "\n" +ROWFACTOR = 0.026 + +class DeviceType(Enum) : + AWRAMS = 1 + SURFACE = 2 + PROFILE = 3 + +class RamsesFunc(Enum): + Lsky = 1 + Esky = 2 + Lwater = 3 + Lw = 4 + Rs = 5 + +class RamsesAWRAMS(Enum): + Lsky = 1 + Esky = 2 + Lwater = 3 + Lw = 4 + Rs = 5 + +class RamsesSURFACE(Enum): + Lsky = 1 + Esky = 2 + Lwater = 3 + Lw = 4 + Rs = 5 + +class RamsesPROFILE(Enum): + Ed = 1 + Esky = 2 + Lu = 3 #upwelling + Lw = 4 + Rs = 5 + +IP_CAL = { + "Incl_Orientation": "up", + "Incl_Xgain": 1.0, + "Incl_Xoffset": 125, + "Incl_Ygain": 0.9375, + "Incl_Yoffset": 126, + "Incl_KBG": 1.2073, + "Incl_Kref": 0.1275, + "Press_Current_mA": 1.08, + "Press_Surface_bar": 5.57, + "Press_Gain": 2.7, + "WithIncl": 1, + "WithPress": 1, + "Press_Sens_mV_bar_4mA": 71.36, + "Press_Sens_mV_bar_1mA": 17.84, + "Press_Type": "PA-10/TAB/10bar", + "CalibrationDate": "08.06.2018", +} + +RAMSES_CAL = { + "SN": "", + "TYPE": "SAM", # SAMIP or SAM + "FUNC": "Lsky", + "inifile": "", + "calfile": "", + "calaqfile": "", + "backfile": "", + "samsn": "", + "b0": [], + "b1": [], + "cal": [], + "calaq": [], + "DarkPixelStart": 237, + "DarkPixelStop": 254, + "Firmware": 2.06, + "IDDataBack": "DLAB_2016-11-29_14-47-59_729_812", + "IDDataCal": "DLAB_2016-12-07_12-00-24_364_510", + "IDDataCalAQ": "DLAB_2016-12-07_12-02-43_591_545", + "IntegrationTime": 0, + "Reverse": 0, + "SerialNo_MMS": 103307, + "WavelengthRange": "310..1100", + "c0s": 299.895, + "c1s": 3.31161, + "c2s": 0.00031652, + "c3s": -1.73194e-06, + "c4s": +0.000000000E+00, + "cs": 102842, + "savefile": "" +} + +class MyConfig(object): + """ + 设置 ID对应的传感器 + """ + + def __init__(self) -> None: + self.device_id = [] + self.device_type = None + self.current_device_id = None + self.system_cfg = {} + self.cfg_path = Path() + self.yml_cfg_file = YAML_FILE_NAME + self.retrieve_cfg_file = Path(RETRIEVE_CFG_FILE) + self.system_cal_cfg = {} + self.validate = { } + + def addDeviceID(self, id:int) -> None: # + self.device_id.append(id) + pass + + def setDeviceID(self, id:int) -> bool: # + if id in self.device_id: + self.current_device_id = id + return True + else: + self.current_device_id = None + return False + pass + + def setDeviceType(self, device_type:DeviceType) -> None: + self.device_type = device_type + pass + + def setRetrieveCfg(self, rtv_yml:str="") -> None: + if rtv_yml =="": + return None + self.retrieve_cfg_file = Path(rtv_yml) + pass + + def getSystemCfg(self,)->None: + ''' + 不同系统,修改此函数,或添加函数 getSystemCfg***()供调用 + ''' + if self.current_device_id == None: + self.system_cfg = None + if self.device_type == None: + self.system_cfg = None + temp_cfg = {} + if self.device_type == DeviceType.AWRAMS: + temp_cfg = { + 1: {"SN": "85B5", "FUNC": RamsesAWRAMS(1).name}, + 2: {"SN": "50ED", "FUNC": RamsesAWRAMS(2).name}, + 3: {"SN": "852F", "FUNC": RamsesAWRAMS(3).name} + } + if self.device_type == DeviceType.SURFACE: + temp_cfg = { + 1: {"SN": "85B5", "FUNC": RamsesSURFACE(1).name}, + 2: {"SN": "50ED", "FUNC": RamsesSURFACE(2).name}, + 3: {"SN": "852F", "FUNC": RamsesSURFACE(3).name} + } + if self.device_type == DeviceType.PROFILE: + temp_cfg = { + 1: {"SN": "85B5", "FUNC": RamsesPROFILE(1).name}, + 2: {"SN": "50ED", "FUNC": RamsesPROFILE(2).name}, + 3: {"SN": "852F", "FUNC": RamsesPROFILE(3).name} + } + self.system_cfg.update( { self.current_device_id : temp_cfg } ) + pass + + def setCfgRamsesSN(self, sn_cfg: dict)->None: + if len(sn_cfg) == 0: + return None + + for k in self.system_cfg[self.current_device_id].keys(): + if str(k) in sn_cfg.keys() : + self.system_cfg[self.current_device_id][k]["SN"] = sn_cfg[str(k)] + else: + self.system_cfg[self.current_device_id][k]["SN"] = None + # if k in sn_cfg.keys() : + # self.system_cfg[self.current_device_id][k]["SN"] = sn_cfg[k] + pass + + def setSystemCalCfg(self, sn_cfg: dict)->None: + if len(sn_cfg) == 0: + pass + + def getDictByAttr(self, *args) -> dict: + ret = {} + if len(args) == 0: + return ret + if len(args) == 1: + if not hasattr(self, args[0]): + return ret + tmp = getattr(self, args[0]) + if isinstance(tmp, dict): + ret.update(tmp) + return ret + if len(args) == 2: + if not hasattr(self, args[0]): + return ret + if not isinstance(getattr(self, args[0]), dict): + return ret + tmp: dict = getattr(self, args[0]) + if not tmp.__contains__(args[1]): + # print(f"------------{args[1]}") + return ret + tmp2 = tmp[args[1]] + if isinstance(tmp2, dict): + ret.update(tmp2) + return ret + if len(args) > 2: + return ret + pass + + # 设置字典对应的键值 + def set_attr(self, d: dict, k, v) -> bool: + if d.__contains__(k): + d.update({k: v}) + return True + return False + + def write_yaml(self, d: dict): + with open(self.yml_cfg_file, "w", encoding="utf-8") as f: + yaml.dump(d, f) + + def read_yaml(self ) -> dict: + with open(self.yml_cfg_file, "r", encoding="utf-8") as f: + content = f.read() # conent 读出来是字符串 + d = yaml.load(content, Loader=yaml.FullLoader) # 用load方法转字典 + return d + + def write_rtv_yaml(self, d: dict): + with open(self.retrieve_cfg_file, "w", encoding="utf-8") as f: + yaml.dump(d, f) + + def read_rtv_yaml(self ) -> dict: + with open(self.retrieve_cfg_file, "r", encoding="utf-8") as f: + content = f.read() # conent 读出来是字符串 + d = yaml.load(content, Loader=yaml.FullLoader) # 用load方法转字典 + return d + + def get_retrieve(self) -> dict: + retrieve = {} + retrieve.update({"beginWL": BEGIN_WAVELENGTH}) + retrieve.update({"endWL": END_WAVELENGTH}) + retrieve.update({"interval": INTERVAL}) + retrieve.update({"rowFactor": ROWFACTOR}) + return retrieve + pass + +ramses_buf_str= "\ + 23a0000007fefe0a0781067d067d068e0693069c069c06b006b506cb06e40619076607e1076c081509cd09bb0a7d0bee0b1d0c6d0cca0ca40ddc0f30135b18b4224d320e43f852c8\ + 23a0000006fefe17639c71c97c9484bb89358be98e5d98b1a37eadccb66abd26be31b97db124aa18a3f29c0499349735968e93a48eea8a028bc28cec8d048f1c92c096de9ab99d43\ + 23a0000005fefee0a157a9ecb1b1b97dc034c507c741c7d2c65ec550c20dbde9b535ae56a60a9e2296cd8ee887278129798170c669b16503632e61605f3a5def5a8e5862561154be\ + 23a0000004fefe3c51f54dda4a0c48634595426a3f5a3cc539903767362b36cc351f356634b633fc32c4310630fb2ec32fe63199349037e03ac03dc03eae3c303a9639d13a413da7\ + 23a0000003fefe97412746bc49404caa4dc54d374ca646d63bde326b332739e43c503d2b3c363aca37ef342d32c22f782d1d2bd328ec250222101e691b2b1a7119d3184018fa174d\ + 23a0000002fefed3177a17e3160616f81423149313f11233126711d8103b10a40f160f8a0efb0d580d660c6f0bd80aa10a580a000ab4099b0994097109e2082c087a0736072c077d\ + 23a0000001fefe2a071e071607140718071e073c074d076a076e076b076007670763076c0760075c073d07350724071207fb06ef06d706cc06b706a506960684067b0672066306a2\ + 23a0000000fefe58065406500642064e064306470642063f064806410644064306430641064206460640063c063e063e063d064406430644063c063c063c063c06400640064906ed\ + 23a0000007fefe0a071b071c07260737073e0749075907650774078b07c0072c08e3082b0ada0be80d9c107b147318931ae51add1a271a77192f1bfb1d99207c265c30c738f03d53\ + 23a0000006fefe07438f489d4d8452d957945cff639171a5832a97deab7fbe09c86cc5acb9d5ab299e90915287de7f8b7ae275ed6f056aff664f662665bc63936335655767926879\ + 23a0000005fefec269206d3e724377fe7b7a8050831f85b68637881689e4884787008580823d7f887bee773d7496702a6cde654c5f895a1f570d5416514d4e9d4bde4897468c44c3\ + 23a0000004fefe71421640db3dc83bbb39533777346c31b92e912c152b5b2aff292129e727cb26d925fd249223b4214020da1fe91ff41f28209420dc201520071e671c221c8d1cfe\ + 23a0000003fefecd1dd31fe72164235924cb24b924f72331211e1ca018ef19221d121f621fe91e081ed51c761b311a2f193c18651788166015a013de11d1106e1041101810e80f2e\ + 23a0000002fefee50fd90fbc0f6d0ff70e610ee00d930d460de40c900c450c010cbd0b7c0b480bfc0aab0a2c0a9e094d092b09fb08d008a208990881087d083908e6078d07660747\ + 23a0000001fefe5b075a07500751074d074e0751075d076807730788077e077c077c07810777077a076c0765075c075607480740073607270723070d070d070b07ff06fd06f0062f\ + 23a0000000fefef606f106ed06f506ef06eb06f106ec06f006e906e806ed06e606ef06e506ea06ec06ee06eb06e906ee06f006ef06ea06e906e606e606e606ec06ea06ea06f506f2\ + 23a0000007fefe0605830479047d047e04810482048204850487048b048c04850487048c049304950498049c04a804a904b604b804c604d004e104f104190546059805ff059a06bb\ + 23a0000006fefe90073209ea0b7610c117cc22b2324a487b645e8798acf2c927d28dc1f2a1ac809664804e543d7a308327a321d81dab1b0f1bca1bb41dba2098243329382e773335\ + 23a0000005fefeca38213e544329486f4c1c500653335592564f577d573b57a556b4557e540a534451424f004d714a9b47994458410e3e9c3af8368c33b630982eca2c052b3429ae\ + 23a0000004fefe632763255a234821321f0e1d061b291983171e16d814a91379124b1138104b0f610e990dd80c240c880bfc0a7b0af8097709020990082508de07c507ba07a50762\ + 23a0000003fefe950781076407460727070007d306ab066e06270605060d0614061306fe05e805d105b405a00586057105630549053d0528051105fd04f304ee04e404dc04dd04c3\ + 23a0000002fefed804d904d004c604bf04b904b904b104a804a604a6049d04980496048f04970491048c04880486047e0484047a047d047b047c0478047a04760476047004700430\ + 23a0000001fefe6f0474046c046d0472046d047304750470046e04760472046f047604700473046f04730470047504700470046d046b047004710470046e046d046a046b046904e4\ + 23a0000000fefe690470046e046b046c04680468046e0466046a046a0469046b046d04640466046c046c046b046a04660466046b046c046a046a0468046f046804740471048d0417\ + " + + +if __name__ == "__main__": + s = RamsesPROFILE + print(s(1)) + print(s(2)) + + cfg = MyConfig() + cfg.addDeviceID(2) + cfg.addDeviceID(3) + cfg.setDeviceType(DeviceType.AWRAMS) + cfg.setDeviceID(2) + cfg.getSystemCfg() + print(cfg.system_cfg) + + d = {"1":"8888","2":["7777"],"3":["9999"]} + cfg.setCfgRamsesSN(d) + print("修改后。。。。。\n") + print(cfg.system_cfg) + + # cfg.write_yaml( cfg.system_cfg) + + dd = cfg.read_yaml() + # dd 作为cfg.system_cfg 使用 + for k,v in dd.items(): + print(k) + print(type(k)) + + retrieve = { + "beginWL": 350, + "endWL": 950, + "interval": 1, + "rowFactor": 0.026 + } diff --git a/mypanel.py b/mypanel.py new file mode 100644 index 0000000..8c0db77 --- /dev/null +++ b/mypanel.py @@ -0,0 +1,48 @@ +import wx + +class MyPanel(wx.Panel): + """docstring for MyPanel.""" + def __init__(self, *arg, **kwarg): + super(MyPanel, self).__init__( *arg,**kwarg) + + self.SetBackgroundColour("#F2F2F2") + self.sb = wx.StaticBox( self, label='系统信息', pos = (30,30) ) + + self.sbs = wx.StaticBoxSizer( self.sb, orient=wx.VERTICAL ) + + self.vbox1 = wx.BoxSizer(wx.VERTICAL) + self.staticText0 = wx.StaticText(self , label='',size=(60, 30), style=wx.ALIGN_CENTRE_VERTICAL ) + + self.staticText1 = wx.StaticText(self, -1,size=(600, -1), + label='''\n上海奕枫仪器设备有限公司 + \n电话: 021-54270075 + \n网站: http://www.yi-win.com + \n邮件: sales@yi-win.com + \n描述: 手持式数据处理 ''' ) + + self.vbox1.Add(self.staticText0, flag=wx.TOP|wx.LEFT, border=5) + self.vbox1.Add(self.staticText1, flag=wx.TOP|wx.LEFT, border=5) + # self.hbox1.Add(self.staticText1, flag=wx.TOP|wx.LEFT, border=5) + # self.hbox1.Add(self.textCtrl1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.vbox1, flag=wx.TOP|wx.LEFT, border= 5) + self.SetSizer(self.sbs) + # self.SetBackgroundColour("#F2F2F2") + # self.vbox = wx.BoxSizer(wx.VERTICAL) + + # # self.vbox.Add(num1, proportion=0, border=8, flag=wx.LEFT) + + # self.sb = wx.StaticBox(self, label='信息') + # self.sbs = wx.StaticBoxSizer(self.sb, orient=wx.VERTICAL) + # self.staticText1 = wx.StaticText(self, -1, + # label='''\n上海奕枫仪器设备有限公司 + # \n电话: 021-54270075 + # \n网站: http://www.yi-win.com + # \n邮件: sales@yi-win.com ''' ) + # self.vbox.Add(self.sbs) + # self.sbs.Add(self.vbox) + # self.SetSizer(self.vbox) + + def setStaticText(self, msg:str): + self.staticText1.SetLabel(msg) + + \ No newline at end of file diff --git a/readcal.py b/readcal.py new file mode 100644 index 0000000..a389d9d --- /dev/null +++ b/readcal.py @@ -0,0 +1,1008 @@ +from tools.mylogger import log +from tools.myexception import MyException +from typing import Tuple,List,Optional,Union,Callable +from pathlib import Path, PurePath +from myconfig import MyConfig,DeviceType,RamsesFunc +from myconfig import FILE_MARK,CURRENT_DIR,CAL_DIR,DATA_DIR,SAVE_EXT_NAME,INTERVAL,SEPARATOR + +class ReadCal(): + def __init__(self) -> None: + pass + + # 数据加时间值 + @staticmethod + def read_columns_set_by_mark(fpath:Path, mark:list, *column ) -> Tuple[str,List] : + # def read_column_1set_by_mark(fpath:str, column:int, *args ) -> Tuple[ str, List ] : + ''' + return: time:str List + mark : ['Spectrum','DATA'] + default end with "[END]" + ''' + log.info(f"read_column_1set_by_mark : \ + {fpath} , mark:{mark} , column:{column}", __name__, "", "") + + # 处理mark args[0] = Spectrum + if len(mark) != 2: + log.error( f"read_column_1set_by_mark() wrong args ",__name__, "", "" ) + raise MyException( f"read_column_1set_by_mark() wrong args " ) + + if len(column) == 0: + log.error(f"read_column_1set_by_mark(), no column para, pls input column ",__name__, "", "" ) + raise MyException( f"read_column_1set_by_mark() , pls input column " ) + + if len( mark ) == 0: + mark_1 = '[Spectrum]' + mark_2 = '[DATA]' + + mark_1 = '['+ mark[0] +']' + mark_2 = '['+ mark[1] +']' + res = [] + sn = ReadCal.readFileSNbyIDDevice(fpath) + # 预备返回数据结构 + # res_time = [] + res_data = [] + columnLen = len(column) + for i in range(columnLen): + res_data.append( [] ) + + with fpath.open('r') as f_handle: + rflag = 0 + # res = [] + # res_time = [] + # res_data = [] + + for line in f_handle: + if mark_1 in line and rflag == 0: + log.debug(f" find {mark_1}", __name__, "", "" ) + rflag += 1 + continue + + if mark_2 in line and rflag > 3 : + log.debug(f" find {mark_1} end ", __name__, "", "" ) + rflag = 0 + continue + + # 获取时间 + if rflag == 1 : + data = line.strip('\n').strip(' ').split('=') + if data[0].strip() == "DateTime" : + log.debug(f" find {mark_1} -> DateTime {data[1]} ", __name__, "", "" ) + time_ = data[1].strip() + rflag += 1 + continue + + if rflag == 2 and ( mark_2 in line ) : + log.debug(f" find {mark_2} -> ", __name__, "", "" ) + rflag += 1 + continue + + if rflag == 3 : + if mark_2 not in line: + # log.debug(f" get data {line}", __name__, "", "" ) + data = line.strip('\n').strip(' ').split(' ') + # 忽略第一行,第一行0开头,保存积分时间的 + if data[0].strip() == "0" : + continue + else: + # if data[1] != "-NAN" and data[1] != "NAN" and data[1] != "+NAN" : + # 处理多列 + for i in range(columnLen): + # res_time.append( time_ ) + res_data[i].append( data[column[i]] ) + continue + + if rflag == 3 and ( mark_2 in line ) : + log.debug(f" find {mark_2} end , line: {line} ", __name__, "", "" ) + rflag += 1 + continue #需要继续让其找到 + + if rflag == 4: + log.debug(f" job done......", __name__, "", "" ) + res_time = time_ + # res_data.append( res ) + # 只读一组数据就 break + rflag += 1 + # res = [] + # rflag = 0 + + if rflag == 5: + log.debug(f" job done, break...", __name__, "", "" ) + break + return ( res_time, res_data) + pass + + # 数据加时间值 + @staticmethod + def read_columns_sets_by_mark(fpath:Path, mark:list, *column + ) -> Tuple[List[str],List[List]] : + # def read_column_1set_by_mark(fpath:str, column:int, *args ) -> Tuple[ str, List ] : + ''' + @desc: 获取多列数据,且为多套数据,非单套数据 + @return: time:List, List + @args : ['Spectrum','DATA'] + default end with "[END]" + ''' + log.info(f"read_column_1set_by_mark : \ + {fpath} , mark:{mark} , column:{column}", __name__, "", "") + + # 处理mark args[0] = Spectrum + if len(mark) != 2: + log.error( f"read_columns_sets_by_mark() wrong args ",__name__, "", "" ) + raise MyException( f"read_columns_sets_by_mark() wrong args " ) + + if len(column) == 0: + log.error(f"read_columns_sets_by_mark(), no column para, pls input column ",__name__, "", "" ) + raise MyException( f"read_columns_sets_by_mark() , pls input column " ) + + if len( mark ) == 0: + mark_1 = '[Spectrum]' + mark_2 = '[DATA]' + + mark_1 = '['+ mark[0] +']' + mark_2 = '['+ mark[1] +']' + res = [] + sn = ReadCal.readFileSNbyIDDevice(fpath) + # 预备返回数据结构 + res_data = [] + res_time = [] + res = [] + columnLen = len(column) + for i in range(columnLen): + # res_time.append( [] ) + res.append( [] ) + + with fpath.open('r') as f_handle: + rflag = 0 + + for line in f_handle: + if mark_1 in line and rflag == 0: + log.debug(f" find {mark_1}", __name__, "", "" ) + rflag += 1 + continue + + if mark_2 in line and rflag > 3 : + log.debug(f" find {mark_1} end ", __name__, "", "" ) + rflag = 0 + continue + + # 获取时间 + if rflag == 1 : + data = line.strip('\n').strip(' ').split('=') + if data[0].strip() == "DateTime" : + log.debug(f" find {mark_1} -> DateTime {data[1]} ", __name__, "", "" ) + time_ = data[1].strip() + rflag += 1 + continue + + if rflag == 2 and ( mark_2 in line ) : + log.debug(f" find {mark_2} -> ", __name__, "", "" ) + rflag += 1 + continue + + if rflag == 3 : + if mark_2 not in line: + # log.debug(f" get data {line}", __name__, "", "" ) + data = line.strip('\n').strip(' ').split(' ') + # 忽略第一行,第一行0开头,保存积分时间的 + if data[0].strip() == "0" : + continue + else: + # if data[1] != "-NAN" and data[1] != "NAN" and data[1] != "+NAN" : + # 处理多列 + for i in range(columnLen): + # res_time.append( time_ ) + res[i].append( data[column[i]] ) + continue + + if rflag == 3 and ( mark_2 in line ) : + log.debug(f" find {mark_2} end , line: {line} ", __name__, "", "" ) + rflag += 1 + continue #需要继续让其找到 + + if rflag == 4: + log.debug(f" job done......", __name__, "", "" ) + res_time.append( time_ ) + res_data.append( res ) + rflag += 1 + # res = [] + # rflag = 0 + + if rflag == 5: + log.debug(f" job done, break...", __name__, "", "" ) + rflag = 0 + continue + + log.debug(f" res.time len {len(res_time)} , \ + res.data len {len(res_data)} , ", __name__, "", "" ) + + return ( res_time, res_data) + + # 数据加时间值 + @staticmethod + def read_columns_sets_by_mark_callback(fpath:Path, mark:list, callback:Callable, *column ) : + ''' + @desc: 获取多列数据,且为多套数据,非单套数据 + @return: time:List, List + @args : ['Spectrum','DATA'] + default end with "[END]" + ''' + log.debug(f"read_column_1set_by_mark : \ + {fpath} , mark:{mark} , column:{column}", __name__, "", "") + + # 处理mark args[0] = Spectrum + if len(mark) != 2: + log.error( f"read_columns_sets_by_mark() wrong args ",__name__, "", "" ) + raise MyException( f"read_columns_sets_by_mark() wrong args " ) + + if len(column) == 0: + log.error(f"read_columns_sets_by_mark(), no column para, pls input column ",__name__, "", "" ) + raise MyException( f"read_columns_sets_by_mark() , pls input column " ) + + if len( mark ) == 0: + mark_1 = '[Spectrum]' + mark_2 = '[DATA]' + + mark_1 = '['+ mark[0] +']' + mark_2 = '['+ mark[1] +']' + + # 预备返回数据结构 + res_data = [] + res_time = [] + res = [] + sn = ReadCal.readFileSNbyIDDevice(fpath) + + columnLen = len(column) + for i in range(columnLen): + # res_time.append( [] ) + res.append( [] ) + + with fpath.open('r') as f_handle: + rflag = 0 + + for line in f_handle: + if mark_1 in line and rflag == 0: + log.debug(f" find {mark_1}", __name__, "", "" ) + rflag += 1 + continue + + if mark_2 in line and rflag > 3 : + log.debug(f" find {mark_1} end ", __name__, "", "" ) + rflag = 0 + continue + + # 获取时间 + if rflag == 1 : + data = line.strip('\n').strip(' ').split('=') + if data[0].strip() == "DateTime" : + log.debug(f" find {mark_1} -> DateTime {data[1]} ", __name__, "", "" ) + time_ = data[1].strip() + rflag += 1 + continue + + if rflag == 2 and ( mark_2 in line ) : + log.debug(f" find {mark_2} -> ", __name__, "", "" ) + rflag += 1 + continue + + if rflag == 3 : + if mark_2 not in line: + # log.debug(f" get data {line}", __name__, "", "" ) + data = line.strip('\n').strip(' ').split(' ') + # 忽略第一行,第一行0开头,保存积分时间的 + if data[0].strip() == "0" : + continue + else: + # if data[1] != "-NAN" and data[1] != "NAN" and data[1] != "+NAN" : + # 处理多列 + for i in range(columnLen): + res[i].append( data[column[i]] ) + continue + + if rflag == 3 and ( mark_2 in line ) : + log.debug(f" find {mark_2} end , line: {line} ", __name__, "", "" ) + rflag += 1 + continue #需要继续让其找到 + + if rflag == 4: + log.debug(f" job done......", __name__, "", "" ) + # callable , not return。 每读出一组就回调,不建议。频繁读写硬盘 + # callback(time_, res) + res_time.append( time_ ) + res_data.append( res ) + rflag += 1 + # res = [] + # rflag = 0 + + if rflag == 5: + log.debug(f" job done, break...", __name__, "", "" ) + rflag = 0 + continue + + # callable , not return。 一个文件读完直接处理 + + callback(sn, res_time, res_data) + + log.debug(f" res.time len {len(res_time)} , \ + res.data len {len(res_data)} , ", __name__, "", "" ) + + # return ( res_time, res_data) + + @staticmethod + def readDataIPinfo(fpath:Path, mark:list, callback:Callable ): + ''' + SAMIP sensor ,Inclination Pressure, InclX InclY Pressure + ''' + log.debug(f"readDataIPinfo : {fpath} , mark:{mark} , ", __name__, "", "") + + # 处理mark args[0] = Spectrum + if len(mark) != 2: + log.error( f"readDataIPinfo() wrong args ",__name__, "", "" ) + raise MyException( f"readDataIPinfo() wrong args " ) + + if len( mark ) == 0: + mark_1 = '[Spectrum]' + mark_2 = '[DATA]' + + mark_1 = '['+ mark[0] +']' + + # 预备返回数据结构 + res_data = [] + res_time = [] + res = [] + tags = ['InclX' , 'InclY', 'Pressure'] + + with fpath.open('r') as f_handle: + rflag = 0 + for line in f_handle: + if mark_1 in line and rflag == 0: + log.debug(f" find {mark_1}", __name__, "", "" ) + rflag += 1 + continue + if mark_1 in line and rflag > 5: + log.debug(f" find {mark_1} end", __name__, "", "" ) + rflag = 0 + continue + # 获取时间 + if rflag == 1 : + data = line.strip('\n').strip(' ').split('=') + if data[0].strip() == "DateTime" : + log.debug(f" find {mark_1} -> DateTime {data[1]} ", __name__, "", "" ) + time_ = data[1].strip() + rflag += 1 + continue + if rflag == 2: + if "[" not in line : + data = line.strip('\n').strip(' ').split('=') + # RAMSES 数据通过MethodName 获得传感器序列号 + if data[0].strip() in tags : + res.append( data[1].strip(' ') ) + rflag += 1 + if rflag == 5: + res_time.append(time_) + res_data.append(res) + rflag = 0 + pass + callback(res_time,res_data) + return (res_time,res_data) + + @staticmethod + def readSamSNFromIni( fpath:Path ): + """ + @description : 依据文件路径获得samsn, 兼容 SAM SAMIP传感器 + """ + + with fpath.open('r') as f_handle: + for line in f_handle: + # IDDevice = SAM_85AF + ln = line.strip('\n').strip(' ').split('=') + if ln[0].strip() == "IDDevice": + if ln[1].strip().split('_')[0] == "SAM": + return ln[1].strip().split('_')[1] + return None + pass + + @staticmethod + def readIPCalFromIni( fpath:Path ): + """ + @description : 依据文件路径获得IPCal IP标定信息 + """ + ipcal = {} + with fpath.open('r') as f_handle: + flag = 0 + for line in f_handle: + # IDDevice = SAM_85AF + ln = line.strip('\n').strip(' ').split('=') + + if flag == 0 and ln[0].strip() == "IDDevice": + if ln[1].strip().split('_')[0] == "IP": + ipcal["IPSN"] = ln[1].strip().split('_')[1] + flag += 1 + continue + + if flag == 1 and "[" in line: + flag += 1 + continue + + if flag == 2: + if "[" in line: + flag = flag + 1 + + if not "[" in line: + line_ = line.strip('\n').strip(' ').split('=') + ipcal.update({line_[0].strip():line_[1].strip()}) + + if flag == 3: + break + + return ipcal + + @staticmethod + def readSAMCalFromIni( fpath:Path ): + """ + @description : 依据文件路径获得SAMCal SAM标定信息 + """ + samcal = {} + with fpath.open('r') as f_handle: + flag = 0 + for line in f_handle: + # IDDevice = SAM_85AF + line_ = line.strip('\n').strip(' ').split('=') + if flag == 0 and line_[0].strip() == "IDDevice": + if line_[1].strip().split('_')[0] == "SAM": + samcal["SAMSN"] = line_[1].strip().split('_')[1] + flag += 1 + continue + + if flag == 1 and "[" in line: + flag += 1 + continue + + if flag == 2: + if "[" in line: + flag = flag + 1 + + if not "[" in line: + line_ = line.strip('\n').strip(' ').split('=') + samcal.update({line_[0].strip():line_[1].strip()}) + + if flag == 3: + break + return samcal + + @staticmethod + def readFileSNbyIDDevice(fpath:Path): + sn_from_file = '' + with fpath.open('r') as f_handle: + rflag = 0 + for line in f_handle: + if '[Spectrum]' in line and '[END]' not in line and rflag == 0: + rflag += 1 + pass + if rflag == 1: + data = line.strip('\n').strip(' ').split('=') + # RAMSES 数据通过MethodName 获得传感器序列号 + if data[0].strip() == "IDDevice": + sn_from_file = data[1].strip(' ').split('_')[1] + break + return sn_from_file + + @staticmethod + def readDatafileSNbyMethodName(fpath:Path): + ''' + SAMIP SAM的数据文件中, MethodName对应的值都是 SAM_{SAMSN} + 读SAMIP的数据,建议用 {SAMSN}的处理 + ''' + sn_from_file = '' + with fpath.open('r') as f_handle: + rflag = 0 + for line in f_handle: + if '[Spectrum]' in line and '[END]' not in line and rflag == 0: + rflag += 1 + pass + if rflag == 1: + data = line.strip('\n').strip(' ').split('=') + # RAMSES 数据通过MethodName 获得传感器序列号 + if data[0].strip() == "MethodName": + sn_from_file = data[1].strip(' ').split('_')[1] + break + return sn_from_file + + +if __name__ == "__main__": + log.info(f"******** main read *********", __name__, "", "") + + # path = PurePath() + # print(path) + + pass + + # def read_data_sn(self,fpath): + # with open(fpath, 'r') as f_handle: + # rflag = 0 + # for line in f_handle: + # if '[Spectrum]' in line and '[END]' not in line and rflag == 0: + # rflag += 1 + # pass + # if rflag == 1 : + # data = line.strip('\n').strip(' ').split('=') + # if data[0].strip() == "IDDevice" : + # return data[1].strip(' ').split('_')[1] + # pass + + # def read_data1(self,fpath): + # with open(fpath, 'r') as f_handle: + # rflag = 0 + # res = [] + # res_time = [] + # res_data = [] + + # for line in f_handle: + # if '[Spectrum]' in line and '[END]' not in line and rflag == 0: + # rflag += 1 + # pass + + # if '[Spectrum]' in line and '[END]' in line : + # rflag = 0 + # pass + + # # 获取时间 + # if rflag == 1 : + # data = line.strip('\n').strip(' ').split('=') + # if data[0].strip() == "DateTime" : + # time_ = data[1].strip() + # rflag += 1 + + # if rflag == 2 and ( '[DATA]' in line or '[Data]' in line ) : + # rflag += 1 + + # if rflag == 3 : + # data = line.strip('\n').strip(' ').split(' ') + + # if int(data[0].strip()) == 0 : + # pass + # else: + # # if data[1] != "-NAN" and data[1] != "NAN" and data[1] != "+NAN" : + + # res.append( float(data[1] ) ) + # if rflag == 3 and '[' in line and ']' in line: + # rflag += 1 + # if rflag == 4: + # # 这个地方 + # # self. __save_absorbance_data( res_time, res, sn ) + # res_time.append( time_ ) + # res_data.append( res ) + # # ?? 可以调用函数直接处理 + # # DealResult.deal_one_data(time_,res) + # res = [] + # rflag = 0 + # # return [['data']] + # pass + + + # def read_data_column( self,fpath, column=1 ): + # column_ = 1 + # if int(column_) : + # column_ = int(column_) + # pass + # else: + # pass + + # with open(fpath, 'r') as f_handle: + # rflag = 0 + # res = [] + # res_time = [] + # res_data = [] + + # for line in f_handle: + # if '[Spectrum]' in line and '[END]' not in line and rflag == 0: + # rflag += 1 + # pass + + # if '[Spectrum]' in line and '[END]' in line : + # rflag = 0 + # pass + + # # 获取时间 + # if rflag == 1 : + # data = line.strip('\n').strip(' ').split('=') + # if data[0].strip() == "DateTime" : + # time_ = data[1].strip() + # rflag += 1 + + # if rflag == 2 and ( '[DATA]' in line or '[Data]' in line ) : + # rflag += 1 + + # if rflag == 3 : + # data = line.strip('\n').strip(' ').split(' ') + + # if int(data[0].strip()) == 0 : + # pass + # else: + # res.append( float(data[column_] ) ) + # if rflag == 3 and '[' in line and ']' in line: + # rflag += 1 + # if rflag == 4: + # # 这个地方 + # # self. __save_absorbance_data( res_time, res, sn ) + # # res_time.append( time_ ) + # # res_data.append( res ) + # # ?? 可以调用函数直接处理 + # return time_, res + + # # return [['data']] + # pass + + # def read_data_wl( self, fpath ): + # wl = self.read_data_column( fpath, column=0 ) + # pass + + # def get_cal_file(self,sn): + # sn_ = sn + # file_ = {} + # if open( os.path.join( CAL_PATH, "SAM_"+sn_+"ini" ),"r"): + # file_ = { + # "type": "SAM", + # "back":"Back_SAM_", + # "cal":"Cal_SAM_", + # "calaq":"CalAQ_SAM_", + # "ini":"SAM_", #ini + # "immersion":"immersion_factors_Lu.DAT" + # } + # return file_ + # if open( os.path.join( CAL_PATH, "SAMIP_"+ sn_ +"_ALL.ini" ),"r"): + # file_ = { + # "type": "SAMIP", + # # "back":"Back_SAM_" + sn_ + CAL_EXT_NAME, + # # "cal":"Cal_SAM_" + sn_ + CAL_EXT_NAME, + # # "calaq":"CalAQ_SAM_" + sn_ + CAL_EXT_NAME, + # "ini":"SAMIP_"+sn+"_ALL.ini", #ini + # "immersion":"immersion_factors_Lu.DAT" + # } + # if file_['ini'] : + # samsn = self.read_ini(file_['ini'], "SAMSN") + # file_.update("cal", "Cal_SAM_" + samsn + CAL_EXT_NAME) + # file_.update("calaq", "CalAQ_SAM_" + samsn + CAL_EXT_NAME) + # file_.update("back", "Back_SAM_" + samsn + CAL_EXT_NAME) + # return file_ + # return + + # def read_cal(self,sn): + # # SAM SAMIP 不同 + # self.cal_data= {} + # # 1. 依据序列号读 ini, 判读是否有文件 SAM_8578.ini SAMIP_50BB_ALL.ini + # self.calfile = self.get_cal_file(sn) # 其中sam的是错误的 + + # # 2 读ini 文件错误 + + # cal_data = {} + # for key in self.calfile: + # if key == "immersion" : + # path_ = os.path.join( CAL_PATH, self.calfile[key] ) + # content_ = [self.read_data_column( path_, column=0 )[1]] + # content_.append( self.read_data_column( path_, column=0 )[1] ) + # cal_data.update({key:content_}) + + # if key == "cal" : + + # path_ = os.path.join( CAL_PATH, self.calfile[key] ) + # content_ = self.read_data_column( path_, column=0 ) + # cal_data.update({key:content_}) + + # if key == "back" : + # path_ = os.path.join( CAL_PATH, self.calfile[key] ) + # content_ = self.read_data_column( path_, column=0 ) + # cal_data.update({key:content_}) + + # if key == "calaq" : + # path_ = os.path.join( CAL_PATH, self.calfile[key] ) + # content_ = self.read_data_column( path_, column=0 ) + # cal_data.update({key:content_}) + + # if key == "ini" : + # cal_data.update({ "samcal" : self.read_ini( os.path.join( CAL_PATH, self.calfile[key] ), "SAMCAL" ) }) + # cal_data.update({ "ipcal" : self.read_ini( os.path.join( CAL_PATH, self.calfile[key] ), "IPCAL" ) }) + + # pass + + # DealResult.deal_cal(cal_data) + + # pass + + # def read_data(self,fname,lst): + # """ + # @description : 线程守护读取数据文件 ,循环读取 + # 考虑一次读取多组,只读一列的情况 + # sn ,begin,end, 指定读的列 + # 返回:[ [[第一组时间],[第二组时间] .... ], [ [第一组data],[第二组data] ...] ] + # RAMSES 要考虑 : InclX = -6.42, InclY = -6.5625 , Pressure = 6.61394049205538 + # 需要读一组波长出来 + # """ + # log.info( ":::::::::::: Class : %s -> Function :__read_data " % ( __name__, ) ) + # log.info( " __read_data : lst %s" % ( lst, ) ) + # sn = lst[0] + # begin = lst[1] + # end = lst[2] + # column = lst[3] + # samip_sn= lst[4] + + # # 检查 sn--- 不检查sn ,读数据就 成csv + + # # 读取一组数据的0列作为波长??? + + # # if is_sn_ok : + + # log.info( "正在处理文件 .... " + fname ) + # with open(fname, 'r') as f_handle: + # time_ = "" + # rflag = 0 + # intlx = 0.0 + # intly = 0.0 + # pressure = 0.0 + # res = [] + # res_time = [] + # res_data = [] + + # for line in f_handle: + # if rflag == 0 and '[Spectrum]' in line and '[END]' not in line : + # rflag += 1 + # pass + + # if '[Spectrum]' in line and '[END]' in line : + # rflag = 0 + # pass + + # # 获取时间, InclX, InclY ,Pressure + # if rflag == 1 : + # data = line.strip('\n').strip(' ').split('=') + # if data[0].strip() == "DateTime" : + # time_ = data[1].strip() + # rflag += 1 + # # InclX, InclY ,Pressure + + # if rflag == 2: + # data = line.strip('\n').strip(' ').split('=') + + # if data[0].strip() == "InclX" : + # intlx = data[1].strip() + + # if data[0].strip() == "InclY" : + # intly = data[1].strip() + + # if data[0].strip() == "Pressure" : + # pressure = data[1].strip() + + + # # DATA set 结束添加数据 + # if rflag == 4 and '[DATA]' in line and '[END]' in line: + # # time.sleep(10) + # res_time.append( [time_,intlx,intly,pressure] ) + # res_data.append( res ) + # res = [] + # rflag += 1 + + # if rflag == 3 : + # data = line.strip('\n').strip(' ').split(' ') + # # print("rflag %s +++++++++++++++++++++++++++++++++ %s" %(rflag,data) ) + # if data[0] != "0" and data[1] != "-NAN" and data[1] != "NAN" and data[1] != "+NAN" : #去掉第一行 0, 对应的积分时间 2^(n+1) + # # print("append %s -- %s" %(data[0],data[1]) ) + # res.append( float( data[column-1] ) ) + # if data[0] != "0" and float(data[0]) > 950 : + # # print("> 950... %s %s" %(data[0],data[1]) ) + # rflag += 1 + + # # 处理data 部分 + # if rflag == 2 and '[DATA]' in line and '[END]' not in line: + # # print("rflag %s +++++++++++++++++++++++++++++++++ data+1 " %(rflag,) ) + # rflag += 1 + + + # if rflag == 5: + # DealResult.deal_ramses_data(time_, [[intlx,intly,pressure], res]) + # # 这个地方 + # # self. __save_absorbance_data( res_time, res, sn ) + # # print("rflag 4 ......................") + # # res_time.append( [time_,intlx,intly,pressure] ) + # # print(" append time %s " %res_time) + # # res_data.append( res ) + # res = [] + # rflag = 0 + # intlx = 0.0 + # intly =0.0 + # pressure =0.0 + # # else: + # # return [] + + # log.info( "已经转换完文件,正在保存... " + fname ) + + # # 分析处理数据,还是返回原始数据 或空 ?? + # log.info( " Function :__read_data %s - %s " % ( res_time[0] ,res_data[0] ) ) + + + # # # 光强保存文件路径 + # # fpath = os.path.join(INTENSITY_PATH, samip_sn + SAVE_EXT_NAME ) + # # fpath_IP = os.path.join(INTENSITY_PATH, samip_sn + "_IP" + SAVE_EXT_NAME ) + + # # for i in range ( len(res_time) ) : + # # # print("1111111111..............%s %s " %(res_time[i],res_time[i][0]) ) + # # # time.sleep(2) + # # ProcessFile.save_time_list( str(res_time[i][0]) , res_data[i], TOKEN, fpath ) + # # # 不是samip 不保存 IP 文件 + # # if sn != samip_sn: + # # ProcessFile.save_time_list( str(res_time[i][0]) , res_time[i][1:], TOKEN, fpath_IP ) + + + # # log.info( "保存结束 ... " + fname ) + + # # 返回 ok 表示文件处理结束 + # return + # pass + + # def read_ini(self,fname ,type_): + # """ + # @description : 三个不同任务, SAM SN, SAM ATTR, IP ATTR + # 分别记为 SAMSN SAMCAL IPCAL + # """ + # log.info( " RAMSES __read_ini -> lst -> %s " % type_) + # typ = type_ + # data = [] + + # if typ == "SAMSN" : + + # with open(fname, 'r') as f_handle: + # for line in f_handle: + # # IDDevice = SAM_85AF + # ln = line.strip('\n').strip(' ').split('=') + # if ln[0].strip() == "IDDevice" : + # if ln[1].strip().split('_')[0] =="SAM" : + # return ln[1].strip().split('_')[1] + # pass + + # if typ == "SAMCAL" : + # samcal= {} + # with open(fname, 'r') as f_handle: + # flag = 0 + # for line in f_handle: + # # IDDevice = SAM_85AF + # line_ = line.strip('\n').strip(' ').split('=') + # if flag == 0 and line_[0].strip() == "IDDevice" : + # if line_[1].strip().split('_')[0] =="SAM" : + # samcal["SAMSN"] = line_[1].strip().split('_')[1] + # flag += 1 + + # if flag == 2 and "[END]" in line: + # flag += 1 + + # if flag == 2: + # # print(" 1 %s %s %s" % (fname,line_[0],line_[1])) + # samcal[line_[0]] = line_[1] + + # if flag == 1 and line_[0].strip() == "[ATTRIBUTES]" : + # flag += 1 + + # if flag == 2 and "[END]" in line: + # flag += 1 + + # return samcal + + # pass + + # if typ == "IPCAL" : + # ipcal= {} + # with open(fname, 'r') as f_handle: + # flag = 0 + # for line in f_handle: + # # IDDevice = SAM_85AF + # ln = line.strip('\n').strip(' ').split('=') + + # if flag == 0 and ln[0].strip() == "IDDevice" : + # if ln[1].strip().split('_')[0] =="IP" : + # ipcal["IPSN"] = ln[1].strip().split('_')[1] + # flag += 1 + + # if flag == 2 and "[END]" in line: + # flag += 1 + + # if flag == 2: + # ipcal[ln[0]] = ln[1] + + # if flag == 1 and ln[0].strip() == "[ATTRIBUTES]" : + # flag += 1 + + # return ipcal + + # return + # pass + + # def read_raw( self, fname , lst, uiraw): + # """ + # @description : 三个不同任务, SAM SN, SAM ATTR, IP ATTR + # 对波长进行标定处理 + # 并存入文件 + # λ(N) = C0s + C1s·N + C2s· N2 + C3s·N3 + # """ + + # sep = uiraw["1"] + # air_water = int(uiraw["2"]) + + # with open(fname, 'r') as f_handle: + # sn = "" + # wl = "" + # is_samip = 0 + # # data = data[2:] + # # cal_data = lst[sn] + # wl_cal = [] + # cal_data = [] + # intg_time = 128 + # ip_cal = [] + # cal = [] + # calaq = [] + # b0 = [] + # b1 = [] + + # for line in f_handle: + # data = line.split(",") + # sn_d = data[0] + + # if sn_d != sn : + # sn = sn_d + # intg_time = int( data[1] ) + # cal_data = lst[sn] + # # 判断sam SAMIP + # if cal_data[0][0] != cal_data[0][1] : + # is_samip = 1 + + # wl_cal = cal_data[1] + # ip_cal = cal_data[2] + + # if air_water == 1 : + # cal = cal_data[3] + # else: + # cal = cal_data[2] + + # b0 = cal_data[4] + # b1 = cal_data[5] + + # for i in range(1,256): + # temp = float(wl_cal["C0s"]) + \ + # float(wl_cal["C1s"]) * i + \ + # float(wl_cal["C2s"]) * i * i + \ + # float(wl_cal["C3s"]) * i *i *i + # wl.append(temp) + + + + # # 处理数据 + # data = data[2:] + # intensity = [] + # Cn = [] + + # for i in range( 255 ): + # # NAN 为 0 + # # if cal[i] = "+NAN": + # # intensity.append(0) + # # else: + # Mn = data[i] / 65535 + # Bn = float( b0[i] ) + float( b1[i] ) * intg_time / 8192 #积分时间比 + # Cn.append(Bn - Mn) + + # offset = 0 # DarkPixelStart = 237 DarkPixelStop = 254的平均值. 数组中236-254 + # for i in range( int( wl_cal['DarkPixelStart']) -1 , int( wl_cal['DarkPixelStop']) ): + # offset = offset + float( Cn[i] ) + # offset = offset/ ( int( wl_cal['DarkPixelStop']) - int( wl_cal['DarkPixelStart']) +1 ) + + # for i in range( 255 ): + # Dn = Cn[i] - offset + # En = 8192 * Dn / intg_time + + # # ???? Sn 来自 cal calaq 文件的部分 + # Sn = cal[i] + # intensity.append( En / Sn ) + + # # 还需要处理传感器的 IP + # if is_samip : + # # ip 数据过来后的格式 + # pass + + # return intensity + + # # 数据分别写到文件 diff --git a/retrieve.yml b/retrieve.yml new file mode 100644 index 0000000..ba0f0ee --- /dev/null +++ b/retrieve.yml @@ -0,0 +1,4 @@ +beginWL: 350 +endWL: 950 +interval: 1 +rowFactor: 0.026 diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tools/myexception.py b/tools/myexception.py new file mode 100644 index 0000000..1b526c0 --- /dev/null +++ b/tools/myexception.py @@ -0,0 +1,11 @@ +class TCPIPException(Exception): + def __init__(self, message="TCPIP 自定义异常"): + self.message = "TCPIP exception : " + message + +class SerialException(Exception): + def __init__(self, message="Serial 自定义异常"): + self.message = "serial exception : " + message + +class MyException(Exception): + def __init__(self, message=" 自定义异常"): + self.message = "自定义异常: " + message \ No newline at end of file diff --git a/tools/mylogger.py b/tools/mylogger.py new file mode 100644 index 0000000..9c85ec9 --- /dev/null +++ b/tools/mylogger.py @@ -0,0 +1,285 @@ +# coding=utf-8 +''' +单例模式日志 -- 使用一次关闭 handler +这种方法优缺点: +缺点: 输出的format 需要自己定义 ,并过滤 + 过滤要看是否以什么开头,或包含什么 +优点: 不占用文件资源,占用系统资源小 +调用 log.info( ) log.error() +''' + +import logging +import logging.handlers +import os +import time +import threading +# from config import LOG_PATH,LOG_LEVEL,LOG_ENABLED,LOG_FORMAT, \ +# LOG_TO_CONSOLE,LOG_TO_FILE + +MY_LOGGER_NAME = "DefaultLogger" +LOG_ENABLED = True # 是否启用日志 +LOG_TO_CONSOLE = True # 是否启用控制台输出日志 +LOG_TO_FILE = False # 是否启用文件输出 +LOG_COLOR_ENABLE = True # 是否启用颜色日志 + +LOGGER_DIR = "logs" +LOGGER_PATH = os.path.join( os.path.dirname(__file__), LOGGER_DIR ) +LOGGER_FILENAME = os.path.join( LOGGER_PATH, 'logs.log' ) + +""" +logging.INFO , logging.DEBUG , logging.WARNING , logging.ERROR , +""" +LOG_LEVEL = logging.INFO # 日志等级DEBUG INFO WARNIG ERROR +# LOG_LEVEL = logging.DEBUG +# LOG_LEVEL = logging.WARNING + +""" +# LOG_FORMAT = " %(name)s - %(module)s - %(filename)s - %(lineno)d | %(levelname)s : %(message)s" +# LOG_FORMAT = "%(levelname)s - %(asctime)s - process: %(process)d - threadname: %(thread)s " \ +# "- %(filename)s - %(funcName)s - %(lineno)d - %(module)s " \ +# "- %(message)s " +# LOG_FORMAT = "%(asctime)s - %(thread)s " \ +# "- %(levelname)s ::: %(message)s " +# '[%(asctime)s] |%(thread)s| %(levelname)-6s: %(message)s' +# fm = '%(levelname):%(levelno)s:%(name)s:%(funcName)s:%(asctime):%(pathname):%(filename):%(module):%(thread):%(threadName)' +# 此处日志颜色,修改日志颜色是通过 Filter实现的 +""" +LOG_FORMAT = '%(levelname)s\t[%(asctime)s] %(package)s:%(classname)s:%(funcname)s \t>> %(message)s' + +""" +# 此处日志颜色,修改日志颜色是通过 Filter实现的 +""" +LOG_FORMAT_COLOR_DICT = { + 'ERROR' : "\033[31mERROR\033[0m", + 'INFO' : "\033[36mINFO\033[0m", + 'DEBUG' : "\033[1mDEBUG\033[0m", + 'WARN' : "\033[33mWARN\033[0m", + 'WARNING' : "\033[33mWARNING\033[0m", + 'CRITICAL': "\033[35mCRITICAL\033[0m", +} + +""" +# Filter 用法, 以package class function 过滤 __package__ __class__ +# log.error( f"{__package__}::{__class__.__name__}::{sys._getframe().f_code.co_name} >> ") +# log.error( f"PacakgeName::ClassName::FunctionName:: ") +# LOGGER_FILTER_PACKAGE=[] 为空, 则Filter不起作用 +# 不为空,则只显示定义的报名 +# LOGGER_FILTER_CLASS=[] 为空, 则Filter不起作用 +# 不为空,则只显示定义的类或 +# LOGGER_FILTER_FUNCNAME=[] 为空, 则Filter不起作用 +# 不为空,则只显示定义的函数 +""" +# LOGGER_FILTER_PACKAGE = [ "test_logger" ] # 包名,文件名去 .py?? +LOGGER_FILTER_PACKAGE = [ ] +LOGGER_FILTER_CLASS = [ ] # 类名,文件名去 .py?? +# LOGGER_FILTER_CLASS = [ "LogTest" ] +# LOGGER_FILTER_FUNCNAME = [ "test1","test" ] # 函数名 +LOGGER_FILTER_FUNCNAME = [ ] +LOGGER_FILTER_LEVELNAME = [ ] # INFO DEBUG WARNING + +class PackageFilter(logging.Filter): + def __init__(self, filter_word:list = []): + self.filter_word = filter_word + pass + def filter(self, record: logging.LogRecord) -> bool: + if self.filter_word is not None: + return record.package in self.filter_word + +class ClassFilter(logging.Filter): + def __init__(self, filter_word:list = []): + self.filter_word = filter_word + pass + def filter(self, record: logging.LogRecord) -> bool: + if self.filter_word is not None: + return record.classname in self.filter_word + + pass + +class FunctionFilter(logging.Filter): + def __init__(self, filter_word:list = []): + self.filter_word = filter_word + pass + def filter(self, record:logging.LogRecord) -> bool: + if self.filter_word is not None: + return record.funcname in self.filter_word + +class LevelNameFilter(logging.Filter): + def __init__(self, filter_word:list = []): + self.filter_word = filter_word + pass + def filter(self, record:logging.LogRecord) -> bool: + if self.filter_word is not None: + return record.levelname in self.filter_word + +class ColorFilter(logging.Filter): + def __init__(self,): + pass + def filter(self, record: logging.LogRecord) -> bool: + record.levelname = LOG_FORMAT_COLOR_DICT.get(record.levelname) + return True + +class Log(object): + _instance_lock = threading.Lock() + + def __new__(cls, *args, **kwargs): + if not hasattr(Log, "_instance"): + with Log._instance_lock: + if not hasattr(Log, "_instance"): + Log._instance = object.__new__(cls) + return Log._instance + + def __init__(self, loggername = "DefaultLog" ): + # 文件命名 os.path.join(): 将多个路径组合后返回 + self.logger_filepath = LOGGER_FILENAME + self.loggername = loggername + self.level = LOG_LEVEL + + # 日志输出格式 + fm = LOG_FORMAT + self.formatter = logging.Formatter( fm ) + + # 生成记录器对象 + self.logger = logging.getLogger( self.loggername ) + self.logger.setLevel(LOG_LEVEL) + + # 日志过滤 + self.__add_filter() + + def __console(self, level, message, extra={} ): + # 添加 handler + self.__add_handler() + + # 判断日志级别 + if level == logging.INFO: + self.logger.info( message, extra=extra) + elif level == logging.DEBUG: + self.logger.debug(message,extra=extra) + elif level == logging.WARNING: + self.logger.warning(message,extra=extra) + elif level == logging.ERROR: + self.logger.error(message,extra=extra) + + # removeHandler在记录日志之后移除句柄,避免日志输出重复问题 + self.__remove_handler() + # if LOG_TO_FILE and self.file_handler: + # self.logger.removeHandler(self.file_handler) + # # 关闭打开的文件 + # self.file_handler.close() + # if LOG_TO_CONSOLE and self.stream_handler: + # self.logger.removeHandler(self.stream_handler) + # # 关闭打开的文件 + # self.stream_handler.close() + pass + + # debug < info< warning< error< critical + # debug模式 + def debug(self, message, package="Unknown", classname="Unknown", funcname="Unknown" ): + self.__console(logging.DEBUG, message, extra={"package":package, "classname":classname, "funcname":funcname} ) + # self.__remove_handler() + # info模式 + def info(self, message, package="Unknown", classname="Unknown", funcname="Unknown" ): + self.__console(logging.INFO, message, extra={"package":package, "classname":classname, "funcname":funcname} ) + # self.__remove_handler() + # warning模式 + def warning(self, message, package="Unknown", classname="Unknown", funcname="Unknown"): + self.__console(logging.WARNING, message, extra={"package":package, "classname":classname, "funcname":funcname} ) + # self.__remove_handler() + + # error模式 + def error(self, message, package="Unknown", classname="Unknown", funcname="Unknown"): + self.__console(logging.ERROR, message, extra={"package":package, "classname":classname, "funcname":funcname} ) + # self.__remove_handler() + + def __add_filter(self ): + if len( LOGGER_FILTER_PACKAGE ) > 0 : + self.logger.addFilter( PackageFilter( filter_word=LOGGER_FILTER_PACKAGE ) ) + if len( LOGGER_FILTER_CLASS ) > 0 : + self.logger.addFilter( ClassFilter( filter_word=LOGGER_FILTER_CLASS ) ) + if len( LOGGER_FILTER_FUNCNAME ) > 0 : + self.logger.addFilter( FunctionFilter( filter_word=LOGGER_FILTER_FUNCNAME ) ) + if len(LOGGER_FILTER_LEVELNAME) > 0 : + self.logger.addFilter( LevelNameFilter( filter_word=LOGGER_FILTER_LEVELNAME ) ) + + def __add_handler(self ): + if LOG_ENABLED and LOG_TO_FILE: + # 考虑使用 RotatingFileHandler TimedRotatingFileHandler防止日志过大 + # RotatingFileHandler("test", "a", 4096, 2, "utf-8") + # TimedRotatingFileHandler(filename=LOG_PATH+"thread_", when="D", interval=1, backupCount=7) + self.file_handler = logging.handlers.TimedRotatingFileHandler(filename=self.logger_filepath, when='D', interval=1, backupCount=30, encoding='utf-8') + # self.file_handler = logging.FileHandler( self.logger_filepath, encoding='utf-8' ) + self.file_handler.setFormatter( self.formatter ) + # self.file_handler.setLevel( LOG_LEVEL ) + # if LOG_COLOR_ENABLE: # 文件日志无需加彩色 + # self.file_handler.addFilter( ColorFilter( ) ) + self.logger.addHandler(self.file_handler) + + if LOG_ENABLED and LOG_TO_CONSOLE: + # 创建一个StreamHandler,用于输出到控制台 + + self.stream_handler = logging.StreamHandler() + self.stream_handler.setFormatter(self.formatter) + # self.stream_handler.setLevel( LOG_LEVEL ) + if LOG_COLOR_ENABLE: + self.stream_handler.addFilter( ColorFilter( ) ) + self.logger.addHandler(self.stream_handler) + + def __remove_handler(self ): + if LOG_TO_FILE and self.file_handler: + self.logger.removeHandler(self.file_handler) + if len(self.logger.handlers)>0: + self.logger.handlers.pop() + # 关闭打开的文件 + self.file_handler.close() + if LOG_TO_CONSOLE and self.stream_handler: + self.logger.removeHandler(self.stream_handler) + if len(self.logger.handlers)>0: + self.logger.handlers.pop() + # 关闭控制台 + self.stream_handler.close() + + def __remove_handler2(self ): + if LOG_ENABLED and LOG_TO_CONSOLE: + self.logger.removeHandler(self.stream_handler) + self.logger.handlers.pop() + # 关闭控制台 + self.stream_handler.close() + if LOG_ENABLED and LOG_TO_FILE: + self.logger.removeHandler(self.file_handler) + self.logger.handlers.pop() + # 关闭打开的文件 + self.file_handler.close() + + +log = Log( loggername = "DefaultLog") + +""" +filename: 指定日志文件名 +filemode: 和file函数意义相同,指定日志文件的打开模式,’w’或’a’ +format: 指定输出的格式和内容,format可以输出很多有用信息。显示的条目可以是以下内容: +%(levelname): 日志级别的名字格式 +%(levelno)s: 日志级别的数字表示 +%(name)s: 日志名字 loggername +%(funcName)s: 函数名字 +%(asctime): 日志时间,可以使用datefmt去定义时间格式,如上图。 +%(pathname): 脚本的绝对路径 +%(filename): 脚本的名字 +%(module): 模块的名字 +%(thread): thread id +%(threadName): 线程的名字 +""" + +""" +文件名行号 函数名, 要在调用的时候想办法了 +# 绝对路径 +print( __file__ ) +print( sys.argv[0] ) + +# 文件名 +print( os.path.basename(__file__) ) +print( os.path.basename(sys.argv[0]) ) + +self.__class__.__name__ +self.__class__.__name__, get_current_function_name() + +logger名 __name__ +""" \ No newline at end of file diff --git a/tools/mypath.py b/tools/mypath.py new file mode 100644 index 0000000..b8f1064 --- /dev/null +++ b/tools/mypath.py @@ -0,0 +1,265 @@ +from pathlib import PurePath, Path + +# from myconfig import NEWLINE,TOKEN,SEPARATOR +""" +""" +class MyDir(object): + """ + 操作方法:设置base tuple_dir header + 设置的是路径, 文件名要 ifNotNewFile 传入 + """ + + def __init__(self) -> None: + self.base_dir = Path() + self.dir_tuple = () + self.header = [] + self.header_str = "" + self.content = [] + self.content_str = "" + self.current_dir = None + self.current_filepath = None + pass + + def getDir(self,): + return self.current_dir + pass + + def setBaseDir(self, dir: Path): + self.base_dir = dir + self.current_dir = self.base_dir + pass + + def setDir(self, t:tuple=()): + self.dir_tuple = t + if len(self.dir_tuple) == 0 : + self.current_dir = self.base_dir + else: + self.current_dir = self.base_dir.joinpath( *t ) + pass + + def getDirFromBaseAndTuple(self, base_dir:Path, dir_tuple: tuple): + '''外部调用返回路径''' + ret_path = base_dir + t = dir_tuple + if len(t) == 0 : + ret_path = ret_path + else: + ret_path = ret_path.joinpath( *t ) + return ret_path + pass + + def setHeader(self, headerlist:list, headerSeperator: str = ";", headerinfo: str = None): + header_str = "" + if len(headerlist) == 0: + return + if headerinfo != None: + header_str = headerinfo + headerSeperator + for hl in headerlist: + header_str = header_str + str(hl) + headerSeperator + self.header_str = header_str[:-1] + pass + + def setContent(self, contentlist: list, contentSeperator: str = ";", contentinfo: str = None): + content_str = "" + if len(contentlist) == 0: + return + if contentinfo != None: + content_str = contentinfo + contentSeperator + tmp_str = "" + for cl in contentlist: + tmp_str = tmp_str + str(cl) + contentSeperator + self.content_str = content_str + tmp_str[:-1] + pass + + def newDirIfNot(self,) -> None: + # self.current_path = self.base_path.joinpath(self.path_tuple) + self.current_dir.mkdir(parents=True, exist_ok=True) + pass + + def newFileIfNot(self, fname: str) -> None: + self.newDirIfNot() + self.current_filepath = self.current_dir.joinpath(fname) + if not self.current_filepath.exists(): + with open(self.current_filepath, 'a') as f: + pass + return + pass + + def getCurrentFileSize(self,): + return self.current_filepath.stat().st_size + + def getFirstline(self,): + first_line = "" + with open(self.current_filepath, 'r') as f: # 打开文件 + first_line = f.readline() # 取第一行 + return first_line.strip('\n').strip('\r') + + def checkHeader(self,) -> int: + ''' + 返回: + 0 : 文件为空,可以直接写header + 1 : header对应上 无需处理 + -1: 需要提醒用户保存数据后,删除文件后再处理 + ''' + if self.getCurrentFileSize() == 0: + return 0 + first_line = self.getFirstline() + # print(f"firstline: {first_line}" ) + # print(f"header_str: {self.header_str}" ) + if first_line == self.header_str: + return 1 + return -1 + pass + + def writeHeader(self,) -> None: + with open(self.current_filepath, "a") as f: + f.write(self.header_str) + return None + pass + + def writeContent(self,new_line="\n") -> None: + with open(self.current_filepath, "a") as f: + f.write(new_line+self.content_str) + return None + pass + + def is_dir_empty(self, ): + '''文件夹是否为空''' + has_next = next(self.current_dir.iterdir(), None) + if has_next is None: + return True + return False + + def is_file_empty(self,): + '''文件是否为空''' + if self.current_dir.stat().st_size ==0: + return True + return False + + def deleteDir(self,): + '''文件夹是否为空''' + try: + if self.current_dir.exists(): + self.current_dir.rmdir() + except OSError as e: + raise Exception(e) + return True + + ## 其他需求 + def get_child_dir(self,) -> list: + ret = [] + tmp_dir = self.current_dir.glob("**/") + for td in tmp_dir: + if td.is_dir(): + ret.append(td.relative_to(self.current_dir)) + return ret + pass + + def get_child_dir_only(self,) -> list: + ret = [] + for d in self.current_dir.iterdir(): + if d.is_dir(): + ret.append(d.relative_to(self.current_dir)) + return ret + pass + + def get_files_from_currentdir(self, fmt:str="*/*" ) -> list: + '''fmt: * */* */*/*''' + ret = [] + tmp_dir = self.current_dir.glob(fmt) + print(tmp_dir) + for td in tmp_dir: + if td.is_file(): + ret.append(td) + return ret + pass + + def sort_dir_and_check( self, dirs:list ): + '''相对目录排序,目录最后一级''' + ret = [] + if len(dirs) == 0: + return ret + tmp = {} + tmp_lst = [] + for d in dirs: + last:str = d.parts[-1] + if last.isdigit() : + tmp.update( {last:d} ) + tmp_lst.append(int(last)) + pass + + tmp_lst.sort() + for t in tmp: + ret.append(tmp.get(str(t))) + pass + return ret + + + def sort_filepath_and_check(self, path_files:list): + '''相对目录排序,目录最后一级''' + ret = [] + if len(path_files) == 0: + return ret + tmp = {} + tmp_lst = [] + for d in path_files: + last:str = d.stem + if last.isdigit() : + tmp.update( {last:d} ) + tmp_lst.append(int(last)) + pass + + tmp_lst.sort() + for t in tmp: + ret.append(tmp.get(str(t))) + pass + return ret + + def group_and_sort_filepath(self,path_files:list): + ret = {} + # dirs_lst = [] + # len_files = len(path_files) + # if len_files == 0: + # return False + # for pf in path_files: + # pf_dir:str = pf.parts[-2] + # if pf_dir.isdigit() and int(pf_dir) not in dirs_lst: + # dirs_lst.append( int(pf_dir) ) + # dirs_lst.sort() + + + + + def check_dirs(self, dirs:list, begin:int =0, step:int=1): + '''检查目录是否从begin开始递增''' + len_dirs = len(dirs) + if len_dirs == 0: + return False + for i in range(begin,len_dirs,step) : + if dirs[i].parts[-1] != str(i) : + return False + return True + + def check_path_files(self,path_files:list,begin:int =0, step:int=1): + '''检查文件名从begin开始递增''' + len_files = len(path_files) + if len_files == 0: + return False + for i in range(begin,len_files,step) : + if path_files[i].stem != str(i) : + return False + return True + +if __name__ == "__main__": + mp = MyDir() + mp.setBaseDir(Path()) + print(mp.current_dir) + # t = ("test_dir","1","11") + t = ("test_dir", ) + mp.setDir( t ) + print(mp.current_dir) + + cd = mp.get_child_dir_only() + c = mp.sort_dir_and_check(cd) + print(cd ) + print(c ) diff --git a/tools/mytime.py b/tools/mytime.py new file mode 100644 index 0000000..3481cf8 --- /dev/null +++ b/tools/mytime.py @@ -0,0 +1,66 @@ +from datetime import datetime, timedelta +# import locale +# locale.setlocale(locale.LC_ALL, '') + +TIME_STR = "2022-06-10 16:16:16" +STD_TIME_STR_FMT = "%Y-%m-%d %H:%M:%S" # 小写y是两位年份 +CUR_TIME_STR_FMT = "%Y-%m-%d %H:%M:%S" + + +class MyTime(object): + """ + 操作方法:设置base tuple_path header + """ + + def __init__(self) -> None: + self.cur_time_str_fmt = "%Y-%m-%d %H:%M:%S" + self.std_time_str_fmt = "%Y-%m-%d %H:%M:%S" + self.cur_time_str = "" + self.std_time_str = "" + self.cur_datetime = "" + pass + + def setCurrentTimeStrFmt(self, s): + self.cur_time_str_fmt = s + pass + + def setStdTimeStrFmt(self, s): + self.std_time_str_fmt = s + pass + + def setCurrentTimeStr(self, s): + self.cur_time_str = s + self.cur_datetime = datetime.strptime(self.cur_time_str, self.cur_time_str_fmt) + pass + + def setStdTimeStr(self, s): + self.std_time_str = s + self.cur_datetime = datetime.strptime( + self.std_time_str, STD_TIME_STR_FMT) + pass + + def Current2STD(self): + # self.cur_datetime = datetime.strptime(self.cur_time_str , CUR_TIME_STR_FMT) + self.std_time_str = datetime.strftime( + self.cur_datetime, STD_TIME_STR_FMT) + pass + + def STD2Current(self, format: str): + # self.cur_datetime = datetime.strptime(self.std_time_str , STD_TIME_STR_FMT) + self.cur_time_str = datetime.strftime( + self.cur_datetime, CUR_TIME_STR_FMT) + pass + + def timeDelta(self, days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0): + self.cur_datetime = self.cur_datetime + \ + timedelta(days=0, seconds=0, microseconds=0, + milliseconds=0, minutes=0, hours=0, weeks=0) + pass + + +if __name__ == "__main__": + s = "2023-02-07 14:02:46" + mt = MyTime() + mt.setCurrentTimeStr(s) + print(mt.cur_datetime) + pass diff --git a/uiconfig/uiabout.py b/uiconfig/uiabout.py new file mode 100644 index 0000000..56a33c7 --- /dev/null +++ b/uiconfig/uiabout.py @@ -0,0 +1,60 @@ +import wx + +# 设置串口参数的对话框类 + +class About(wx.Dialog): + + def __init__(self, *args, **kwds): + + # 参数调入后初始化 + super(About, self).__init__(*args, **kwds) + + self.InitUI() + self.SetSize((400, 400)) + self.SetTitle("使用帮助") + + def InitUI(self): + + self.panel = wx.Panel(self) + self.vbox = wx.BoxSizer(wx.VERTICAL) + + self.sb = wx.StaticBox(self.panel, label='使用帮助') + self.sbs = wx.StaticBoxSizer(self.sb, orient=wx.VERTICAL) + + self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText1 = wx.StaticText(self.panel, + label='''\n上海奕枫仪器设备有限公司 +电话: 021-54270075 +网站: http://www.yi-win.com +邮件: sales@yi-win.com ''' ) + self.hbox1.Add(self.staticText1) + self.sbs.Add(self.hbox1) + + + + self.panel.SetSizer(self.sbs) + + self.hbox_0 = wx.BoxSizer(wx.HORIZONTAL) + self.okButton = wx.Button(self, label=u'确认') + self.closeButton = wx.Button(self, label='关闭') + self.hbox_0.Add(self.okButton) + self.hbox_0.Add(self.closeButton, flag=wx.LEFT, border=5) + + self.vbox.Add(self.panel, proportion=1, + flag=wx.ALL | wx.EXPAND, border=5) + self.vbox.Add(self.hbox_0, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) + + self.SetSizer(self.vbox) + + self.okButton.Bind(wx.EVT_BUTTON, self.OnSave) + self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose) + + + def saveData(self, e): + pass + + def OnClose(self, e): + self.Destroy() + + def OnSave(self, e): + self.EndModal(wx.ID_OK) \ No newline at end of file diff --git a/uiconfig/uihelp.py b/uiconfig/uihelp.py new file mode 100644 index 0000000..8c7a1c7 --- /dev/null +++ b/uiconfig/uihelp.py @@ -0,0 +1,58 @@ +import wx + +# 设置串口参数的对话框类 + +class Help(wx.Dialog): + + def __init__(self, *args, **kwds): + + # 参数调入后初始化 + super(Help, self).__init__(*args, **kwds) + + self.InitUI() + self.SetSize((400, 400)) + self.SetTitle("使用帮助") + + def InitUI(self): + + self.panel = wx.Panel(self) + self.vbox = wx.BoxSizer(wx.VERTICAL) + + self.sb = wx.StaticBox(self.panel, label='使用帮助') + self.sbs = wx.StaticBoxSizer(self.sb, orient=wx.VERTICAL) + + self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText1 = wx.StaticText(self.panel, + label='''\n上海奕枫仪器设备有限公司 +电话: 021-54270075 +网站: http://www.yi-win.com +邮件: sales@yi-win.com ''' ) + self.hbox1.Add(self.staticText1) + self.sbs.Add(self.hbox1) + + self.panel.SetSizer(self.sbs) + + self.hbox_0 = wx.BoxSizer(wx.HORIZONTAL) + self.okButton = wx.Button(self, label=u'确认') + self.closeButton = wx.Button(self, label='关闭') + self.hbox_0.Add(self.okButton) + self.hbox_0.Add(self.closeButton, flag=wx.LEFT, border=5) + + self.vbox.Add(self.panel, proportion=1, + flag=wx.ALL | wx.EXPAND, border=5) + self.vbox.Add(self.hbox_0, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) + + self.SetSizer(self.vbox) + + self.okButton.Bind(wx.EVT_BUTTON, self.OnSave) + self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose) + + + def saveData(self, e): + pass + + def OnClose(self, e): + self.Destroy() + + def OnSave(self, e): + self.EndModal(wx.ID_OK) \ No newline at end of file diff --git a/uiconfig/uisensor.py b/uiconfig/uisensor.py new file mode 100644 index 0000000..a957cc8 --- /dev/null +++ b/uiconfig/uisensor.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +import wx +# from configobj import ConfigObj +from myconfig import MyConfig,RamsesSURFACE +from myconfig import YAML_FILE_NAME + +class UISensor(wx.Dialog): + """ + @description : Sensor 配置 + """ + def __init__(self, parent, id, did): + # 参数调入后初始化 + self.did = did + super(UISensor, self).__init__( parent, id=id ) + self.config = MyConfig() + self.InitUI() + self.SetSize((400, 400)) + self.SetTitle(" 设置页面 串口 采集间隔 ") + + def InitUI(self): + + self.config_sensor = self.config.read_yaml() + # self.sensor = self.config_sensor.get(self.did) + # print(self.config_sensor) + # print(self.sensor) + + self.panel = wx.Panel(self) + self.vbox = wx.BoxSizer(wx.VERTICAL) + + self.sb = wx.StaticBox(self.panel, label='设置页面') + self.sbs = wx.StaticBoxSizer(self.sb, orient=wx.VERTICAL) + + self.hbox1 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText1 = wx.StaticText(self.panel, label='Lsky: ',size=(60, -1), style=wx.ALIGN_CENTRE_VERTICAL ) + self.textCtrl1 = wx.TextCtrl(self.panel, value="",size=(250,25) ) + tmp = self.getSnByDidAndFunc("Lsky",self.did) + if tmp is not None: + self.textCtrl1.SetValue(tmp) + self.hbox1.Add(self.staticText1, flag=wx.TOP|wx.LEFT, border=5) + self.hbox1.Add(self.textCtrl1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.hbox1, flag=wx.TOP|wx.LEFT, border= 5) + + self.hbox2 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText2 = wx.StaticText(self.panel, label='Esky: ' ,size=(60, -1)) + # self.staticText2_1 = wx.StaticText(self.panel, label='分钟 ' ,size=(60, -1)) + self.textCtrl2 = wx.TextCtrl(self.panel, value="",size=(250,25)) + tmp = self.getSnByDidAndFunc("Esky",self.did) + if tmp is not None: + self.textCtrl2.SetValue(tmp) + self.hbox2.Add(self.staticText2, flag=wx.TOP|wx.LEFT, border=5) + self.hbox2.Add(self.textCtrl2,flag=wx.TOP|wx.LEFT, border=5) + # self.hbox2.Add(self.staticText2_1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.hbox2, flag=wx.TOP|wx.LEFT, border=5) + + self.hbox3 = wx.BoxSizer(wx.HORIZONTAL) + self.staticText3 = wx.StaticText(self.panel, label='Lwater: ' ,size=(60, -1)) + # self.staticText3_1 = wx.StaticText(self.panel, label='分钟 ' ,size=(60, -1)) + self.textCtrl3 = wx.TextCtrl(self.panel, value="",size=(250,25)) + tmp = self.getSnByDidAndFunc("Lwater",self.did) + if tmp is not None: + self.textCtrl3.SetValue(tmp) + self.hbox3.Add(self.staticText3, flag=wx.TOP|wx.LEFT, border=5) + self.hbox3.Add(self.textCtrl3,flag=wx.TOP|wx.LEFT, border=5) + # self.hbox3.Add(self.staticText3_1, flag=wx.TOP|wx.LEFT, border=5) + self.sbs.Add(self.hbox3, flag=wx.TOP|wx.LEFT, border=5) + + self.panel.SetSizer(self.sbs) + + self.hbox_0 = wx.BoxSizer(wx.HORIZONTAL) + self.okButton = wx.Button(self, label=u'保存配置') + self.closeButton = wx.Button(self, label='Close') + self.hbox_0.Add(self.okButton) + self.hbox_0.Add(self.closeButton, flag = wx.LEFT, border=5) + + # 添加 vbox 到panel + self.vbox.Add(self.panel, proportion=1, + flag=wx.ALL | wx.EXPAND, border=5) + + self.vbox.Add(self.hbox_0, flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, border=10) + + self.SetSizer(self.vbox) + + self.okButton.Bind(wx.EVT_BUTTON, self.OnSave) + self.closeButton.Bind(wx.EVT_BUTTON, self.OnClose) + + def getSnByDidAndFunc(self,func,did): + temp:dict = self.config_sensor.get(did) + for v in temp.values(): + if v["FUNC"] == func: + return v["SN"] + return None + pass + + def setSnByDidAndFunc(self,func,did,val): + temp:dict = self.config_sensor.get(did) + for k,v in temp.items(): + if v["FUNC"] == func: + temp[k]['SN'] =val + self.config_sensor.update({did:temp}) + + pass + + def saveData(self, e): + pass + + def OnClose(self, e): + + self.Destroy() + + def OnSave(self, e): + success = True + # 赋值字典,写入文件 + self.setSnByDidAndFunc('Lsky',self.did,self.textCtrl1.GetValue( )) + self.setSnByDidAndFunc('Esky',self.did,self.textCtrl2.GetValue( )) + self.setSnByDidAndFunc('Lwater',self.did,self.textCtrl3.GetValue( )) + print(self.textCtrl3.GetValue( )) + + print(self.config_sensor) + self.config.write_yaml(self.config_sensor) + del self.config + + if success: + self.EndModal(wx.ID_OK) \ No newline at end of file diff --git a/yiwinframe.py b/yiwinframe.py new file mode 100644 index 0000000..4921838 --- /dev/null +++ b/yiwinframe.py @@ -0,0 +1,337 @@ +import wx +import os +import time +import threading +from pathlib import * +# from configobj import ConfigObj + +from listctrl import Listctrl +from mypanel import MyPanel + +from uiconfig.uisensor import UISensor +# from uiconfig.uilogging import UILogging + +from uiconfig.uiabout import About +from uiconfig.uihelp import Help + +from myconfig import TOKEN,DeviceType,YAML_FILE_NAME,RETRIEVE_CFG_FILE +from myconfig import MyConfig +from configuration import Configuration +from handheld import HandHeld,HandHeldBuf + +from tools.myexception import MyException +from tools.mylogger import log + +# -定义菜单ID,关联Event------------------------- +ID_MEASURE = 1 + +ID_SENSOR_SETTING = 11 +ID_LOGGING_SETTING = 12 +ID_CAL_INFO = 13 + +ID_HELP = 21 +ID_ABOUT = 22 + + +class YiwinFrame(wx.Frame): + '''将buf类传进来''' + def __init__(self, title, parent, size=(900, 750)): + self.device_id = 2 + self.device_type = DeviceType.SURFACE.name + self.syscfg = {} + self.sensor_cfg = {} + self.retrieve = {} + self.calinfo_is_ok = False + self.title = title + self.path = PurePath() + # self.save_fname:Path = Path(self.path.joinpath(DATA_FNAME)) + self.result = '' + self.displayData:list =[] + self.interval = 0 + + super(YiwinFrame, self).__init__( parent, title=self.title, size = size ) + + self.BoxSizer = wx.BoxSizer(wx.HORIZONTAL) # 建立一个Boxsizer + self.SetSizer(self.BoxSizer) + self.Centre(wx.BOTH) + + # 建立 listctrl panel 放到BoxSizer + self.listctrl_panel = Listctrl( self ) # 调用自己建立的 Listctrl panel 类 + self.BoxSizer.Add( self.listctrl_panel, proportion =-10, border = 2, flag = wx.ALL | wx.EXPAND) + self.list_ctrl = self.listctrl_panel.list_ctrl + # 隐藏 等待show + self.listctrl_panel.Hide() + + self.mypanel = MyPanel( self ) # 调用自己建立的 Listctrl panel 类 + self.BoxSizer.Add( self.mypanel, proportion =-10, border = 0, flag = wx.ALL | wx.EXPAND) + self.static_text = self.mypanel.staticText1 + # 隐藏 等待show + self.mypanel.Show() + + self.statusBar = self.CreateStatusBar() # 创建状态栏 + self.statusBar.SetFieldsCount(2) # 状态栏分成3个区域 + self.statusBar.SetStatusWidths([-1, -1]) # 区域宽度比列,用负数 + self.statusBar.SetStatusText(u" 等待接收消息......", 0) + + self.__set_menu() # 添加菜单 + self.__attach_events() # 菜单事件 + self.__set_properties() + # self.__read_config() + self.__setTimer() + log.info(f"system init....",__name__, "__init__") + self.mycfg = MyConfig() + self.hh = HandHeld() + + # self.hhb = HandHeldBuf() + + pass + + def __set_menu(self): + ''' + # 设置菜单 + ''' + self.menubar = wx.MenuBar() + + settingMenu = wx.Menu() + settingMenu.Append(ID_SENSOR_SETTING, u'&设置', '...') + settingMenu.AppendSeparator() + settingMenu.Append(ID_CAL_INFO, u'&获取标定信息', ' ') + settingMenu.AppendSeparator() + settingMenu.Append(ID_MEASURE, u'&处理数据', ' ') + # settingMenu.AppendSeparator() + # settingMenu.Append(ID_LOGGING_SETTING, u'&采集设置', ' ') + self.menubar.Append(settingMenu, u'&系统 ') + + aboutMenu = wx.Menu() + aboutMenu.Append(ID_HELP, u'&帮助', 'help...') + aboutMenu.AppendSeparator() + aboutMenu.Append(ID_ABOUT, u'&关于我们', '关于我们...') + self.menubar.Append(aboutMenu, u'&帮助 ') + + self.SetMenuBar(self.menubar) + pass + + def __set_properties(self): + self.SetSize((800, 600)) + # self.SetTitle(u'传感器数据采集--上海奕枫仪器设备有限公司') + self.Centre() + + def __attach_events(self): + ''' + # 绑定菜单事件 + ''' + self.Bind(wx.EVT_MENU, self.OnSensorSetting, id=ID_SENSOR_SETTING ) + self.Bind(wx.EVT_MENU, self.OnCalInfo, id=ID_CAL_INFO ) + # self.Bind(wx.EVT_MENU, self.OnStart, id=ID_MEASURE) + self.Bind(wx.EVT_MENU, self.OnDealData, id=ID_MEASURE) + # self.Bind(wx.EVT_MENU, self.OnLoggingSetting, id=ID_LOGGING_SETTING) + + self.Bind(wx.EVT_MENU, self.OnHelpConfig, id=ID_HELP) + self.Bind(wx.EVT_MENU, self.OnAboutConfig, id=ID_ABOUT) + pass + + def __setTimer(self): + self.timer = wx.Timer(self) #创建定时器,菜单以后 + self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) #绑定一个定时器事件 + pass + + def OnStart( self, event ): + log.info(f"OnStart....interval: {self.interval} min, port: {self.port}") + # self.m = SerialThread() + interval_ms = int(self.interval) * 10 * 1000 + self.timer.Start( interval_ms ) + + def OnStop( self ,event ): + # self.kh.disconnect() + # self.timer.Stop() + pass + + def OnTimer(self, event): + ''' + 定时器实现 + ''' + # log.info( f"OnTimer...." ) + # self.OnDisplaySave() + pass + + def onNotify(self, msg:str): + self.mypanel.setStaticText(msg) + pass + + def __read_config(self,): + # 读取配置文件 + self.mycfg.setDeviceType(DeviceType.SURFACE) + self.sensor_cfg = self.mycfg.read_yaml() + + def OnDealData(self, e)-> None: + log.info(f"OnDealData: 处理测量数据", __name__, "", "") + if not self.calinfo_is_ok: + self.onNotify("Pls get the cal info, and try again" ) + log.warning(f"Pls get the cal info, and try again", __name__, "OnDealData") + self.statusBar.SetStatusText("Pls get the cal info, and try again",0) + pass + + self.hh.getDataFileList() + self.hh.setDeviceID(self.device_id) + self.hh.setRetrieve(self.retrieve) + if self.syscfg != {}: + self.hh.setSyscfg(self.syscfg) + else: + log.warning(f"Pls get the cal info, and try again", __name__, "OnDealData","setCfg") + MyException( f"System Configuration is empty." ) + pass + + if self.hh.dealAllMeasurements( ): + self.onNotify("正在处理数据" ) + self.statusBar.SetStatusText(u" 数据处理完成......", 0) + self.onNotify("处理数据已经结束" ) + pass + + def OnCalInfo(self,e): + '''依据传感器获取标定文件信息''' + ####################################### + self.onNotify("正在获取标定信息") + device_id = self.device_id # 多个设备 + device_type = DeviceType.SURFACE.name + self.mycfg = MyConfig() + + self.mycfg.setDeviceType(DeviceType.SURFACE) + init_para = self.mycfg.read_yaml() + log.info(f"Current Device: {device_type} ", __name__, "", "") + log.info(f"Sensor: {init_para}", __name__, "", "") + # 配置反演需要的参数 波长 间隔 + self.retrieve = self.mycfg.get_retrieve() + log.warning(f"Retrieve: {self.retrieve}", __name__, "", "") + + self.syscfg = {} + + cfgr = Configuration( ) + cfgr.setDeviceType(device_type) + cfgr.setSystemCfgDict(init_para) + + for k,v in init_para.items(): + cfgr.setSystemCfgDict(v) + try: + cfgr.getCalConfiguration() + except Exception as e: + log.error(f"读取配置文件失败. \n {e}",__name__, "", "" ) + raise + log.info(f"v: {cfgr.configuration}", __name__, "", "") + self.syscfg.update({k:cfgr.cal_configuration}) + + # log.warning(f"self.syscfg: {self.syscfg}", __name__, "", "") + log.warning(f"self.syscfg 2: {self.syscfg[2].keys()}", __name__, "", "") + log.warning(f"self.syscfg 3: {self.syscfg[3].keys()}", __name__, "", "") + log.info(f"传感器配置文件读取成功", __name__, "", "") + self.alterStatus_0("传感器配置文件读取成功") + self.onNotify("获取标定信息成功") + self.calinfo_is_ok = True + + pass + + def alterStatus_0(self,msg): + self.statusBar.SetStatusText( msg, 0 ) + + def popDialog(self, msg, msg_type=u"错误提示"): + with wx.MessageDialog( self, msg, msg_type, wx.OK )as dlg: + dlg.ShowModal() + + def OnSensorSetting(self,e): + with UISensor( + self, + -1 , + did = self.device_id ) as Dialog_Sensor_Setting: + Dialog_Sensor_Setting.CenterOnParent() + resultLog = Dialog_Sensor_Setting.ShowModal() + + if resultLog == wx.ID_OK: + print( " Sensor config dialog confirm, call back " ) + self.__read_config() + pass + + def OnHelpConfig(self, e): + with Help( + self, + -1, + "") as Dialog_Help: + resultLog = Dialog_Help.ShowModal() + + if resultLog == wx.ID_OK: + print("Help info") + + pass + + def OnAboutConfig(self, e): + with About( + self, + -1, + "") as Dialog_About: + resultLog = Dialog_About.ShowModal() + + if resultLog == wx.ID_OK: + print("Aboutus") + + pass + + def OnQuit(self, e): + self.Close() + + + +# class SerialThread(threading.Thread): +# """进度条类 """ +# def __init__(self, parent): +# """ +# :param parent: 主线程UI +# """ +# super(SerialThread, self).__init__() # 继承 +# self.parent = parent +# # log.info(f"SerialThread ... {self.parent.kh}") +# self.start() +# self.join() +# # self.setDaemon(True) # 设置为守护线程, 即子线程是守护进程,主线程结束子线程也随之结束。 + + +# def stop(self): +# self.parent.kh.disconnect() +# log.info(" Serial stop.... ") +# pass + + # def run(self): + # log.info(" Serial run.... ") + # wx.CallAfter(self.parent.OnRcv) + + # wx.CallAfter(self.parent.update_process_bar, count) # 调用parent的函数 + # wx.CallAfter(self.parent.close_process_bar) # destroy进度条 + + # def OnSerialThreadStart(self): + # self.m = SerialThread(self) + # pass + + # def OnSerialThreadStop(self): + # self.m.stop() + # pass + + # def OnDisplaySave(self): + # ''' + # 保存数据 self.result + # ''' + # log.info(f"OnDisplaySave ....") + # # self.m = SerialThread(self) + # # self.kh.flush() + # self.OnSerialThreadStart() + + + # def OnRcv( self ): + # log.info(f"OnRcv....") + # self.kh.setPort(self.port) + # if not self.OnDetectPort: + # MyException(f"Can not find port : {self.port}") + # log.info(f"{self.port} ok!") + # # if not self.kh: + # # self.kh = KH3000(self.port) + # # self.result = self.kh.OneMeasure() + # log.info( f"OnRcv success {self.result}", __class__.__name__ ) + # self.OnSave() + # self.OnDisplay() + # pass \ No newline at end of file