Beispiel #1
0
def export_recordeddata_to_file(time_min=None,
                                time_max=None,
                                filename=None,
                                active_vars=None,
                                file_extension=None,
                                append_to_file=False,
                                no_mean_value=False,
                                mean_value_period=5.0,
                                **kwargs):
    '''
    read all data
    '''
    if kwargs.has_key('backgroundtask_id'):
        tp = BackgroundTask.objects.get(id=kwargs['backgroundtask_id'])
        tp.message = 'init'
        tp.timestamp = time()
        tp.pid = str(os.getpid())
        tp.save()
    else:
        if kwargs.has_key('task_identifier'):
            if BackgroundTask.objects.filter(
                    identifier=kwargs['task_identifier'], failed=0):
                return
            else:
                tp = BackgroundTask(
                    start=time(),
                    label='pyscada.export.export_measurement_data_%s' %
                    kwargs['task_identifier'],
                    message='init',
                    timestamp=time(),
                    pid=str(os.getpid()),
                    identifier=kwargs['task_identifier'])
        else:
            tp = BackgroundTask(
                start=time(),
                label='pyscada.export.export_measurement_data_to_file',
                message='init',
                timestamp=time(),
                pid=str(os.getpid()))

        tp.save()

    if type(time_max) in [str, unicode]:
        # convert datestrings
        time_max = mktime(
            datetime.strptime(time_max, "%d-%b-%Y %H:%M:%S").timetuple())
    if type(time_min) in [str, unicode]:
        # convert datestrings
        time_min = mktime(
            datetime.strptime(time_min, "%d-%b-%Y %H:%M:%S").timetuple())

    # add default time_min
    if time_max is None:
        time_max = time()  # now
    if time_min is None:
        time_min = time() - 24 * 60 * 60  # last 24 hours

    # add default extension if no extension is given
    if file_extension is None and filename is None:
        file_extension = '.h5'
    elif filename is not None:
        file_extension = '.' + filename.split('.')[-1]
    # validate filetype
    if not file_extension in ['.h5', '.mat', '.csv']:
        tp.timestamp = time()
        tp.message = 'failed wrong file type'
        tp.failed = 1
        tp.save()
        return
    #
    if filename is None:
        if hasattr(settings, 'PYSCADA_EXPORT'):
            if settings.PYSCADA_EXPORT.has_key('output_folder'):
                backup_file_path = os.path.expanduser(
                    settings.PYSCADA_EXPORT['output_folder'])
            else:
                backup_file_path = os.path.expanduser(
                    '~/measurement_data_dumps')
        else:
            backup_file_path = os.path.expanduser('~/measurement_data_dumps')

        # add filename prefix
        backup_file_name = 'measurement_data'
        if hasattr(settings, 'PYSCADA_EXPORT'):
            if settings.PYSCADA_EXPORT.has_key('file_prefix'):
                backup_file_name = settings.PYSCADA_EXPORT[
                    'file_prefix'] + backup_file_name
        # create output dir if not existing
        if not os.path.exists(backup_file_path):
            os.mkdir(backup_file_path)

        # validate timevalues
        db_time_min = RecordedData.objects.first()
        if not db_time_min:
            tp.timestamp = time()
            tp.message = 'not data to export'
            tp.failed = 1
            tp.save()
            return
        time_min = max(db_time_min.time_value(), time_min)

        db_time_max = RecordedData.objects.last()
        if not db_time_max:
            tp.timestamp = time()
            tp.message = 'not data to export'
            tp.failed = 1
            tp.save()
            return
        time_max = min(db_time_max.time_value(), time_max)

        # filename  and suffix
        cdstr_from = datetime.fromtimestamp(time_min).strftime("%Y_%m_%d_%H%M")
        cdstr_to = datetime.fromtimestamp(time_max).strftime("%Y_%m_%d_%H%M")

        if kwargs.has_key('filename_suffix'):
            filename = os.path.join(
                backup_file_path, backup_file_name + '_' + cdstr_from + '_' +
                cdstr_to + '_' + kwargs['filename_suffix'])
            xml_filename = os.path.join(
                backup_file_path, backup_file_name + '_' + cdstr_from + '_' +
                cdstr_to + '_' + kwargs['filename_suffix'] + '.xml')
        else:
            filename = os.path.join(
                backup_file_path,
                backup_file_name + '_' + cdstr_from + '_' + cdstr_to)
            xml_filename = os.path.join(
                backup_file_path,
                backup_file_name + '_' + cdstr_from + '_' + cdstr_to + '.xml')
    else:  # generate xml file name from filename
        xml_filename = filename.split('.')[0] + '.xml'

    # check if file exists
    if os.path.exists(filename + file_extension) and not append_to_file:
        count = 0
        while os.path.exists(filename + file_extension):
            filename = filename + '_%03.0f' % count

    # append the extension
    filename = filename + file_extension

    # todo add ExportFile  object

    #
    if active_vars is None:
        active_vars = Variable.objects.filter(active=1, device__active=1)
    else:
        if type(active_vars) is str:
            if active_vars == 'all':
                active_vars = Variable.objects.all()
            else:
                active_vars = Variable.objects.filter(active=1,
                                                      device__active=1)
        else:
            active_vars = Variable.objects.filter(pk__in=active_vars,
                                                  active=1,
                                                  device__active=1)

    if mean_value_period == 0:
        no_mean_value = True
        mean_value_period = 5.0  # todo get from DB, default is 5 seconds

    # calulate timevector

    timevalues = arange(
        math.ceil(time_min / mean_value_period) * mean_value_period,
        math.floor(time_max / mean_value_period) * mean_value_period,
        mean_value_period)

    # get Meta from Settings
    if hasattr(settings, 'PYSCADA_META'):
        if settings.PYSCADA_META.has_key('description'):
            description = settings.PYSCADA_META['description']
        else:
            description = 'None'
        if settings.PYSCADA_META.has_key('name'):
            name = settings.PYSCADA_META['name']
        else:
            name = 'None'
    else:
        description = 'None'
        name = 'None'

    if file_extension in ['.h5', '.mat']:
        bf = mat_compatible_h5(filename,
                               version='1.1',
                               description=description,
                               name=name,
                               creation_date=strftime('%d-%b-%Y %H:%M:%S'))
    elif file_extension in ['.csv']:
        bf = excel_compatible_csv(filename,
                                  version='1.1',
                                  description=description,
                                  name=name,
                                  creation_date=strftime('%d-%b-%Y %H:%M:%S'))
    # export config to an separate file to avoid attr > 64k
    export_xml_config_file(xml_filename)

    # less then 24
    # read everything

    if file_extension in ['.h5', '.mat']:
        out_timevalues = [
            unix_time_stamp_to_matlab_datenum(element)
            for element in timevalues
        ]
    elif file_extension in ['.csv']:
        out_timevalues = [
            unix_time_stamp_to_excel_datenum(element) for element in timevalues
        ]

    bf.write_data('time',float64(out_timevalues),\
        id = 0,\
        description="global time vector",\
        value_class = validate_value_class('FLOAT64'),\
        unit = "Days since 0000-1-1 00:00:00")

    tp.max = active_vars.count()

    for var_idx in range(0, active_vars.count(), 10):
        tp.timestamp = time()
        tp.message = 'reading values from database'
        tp.progress = var_idx
        tp.save()
        # query data
        var_slice = active_vars[var_idx:var_idx + 10]
        data = RecordedData.objects.get_values_in_time_range(\
            variable_id__in=list(var_slice.values_list('pk',flat=True)),\
            time_min=time_min,\
            time_max=time_max,\
            query_first_value=True)

        for var in var_slice:
            # write backround task info
            tp.timestamp = time()
            tp.message = 'writing values for %s (%d) to file' % (var.name,
                                                                 var.pk)
            tp.save()
            # check if variable is scalled
            if var.scaling is None or var.value_class.upper() in [
                    'BOOL', 'BOOLEAN'
            ]:
                value_class = var.value_class
            else:
                value_class = 'FLOAT64'
            # read unit
            if hasattr(var.unit, 'udunit'):
                udunit = var.unit.udunit
            else:
                udunit = 'None'

            if not data.has_key(var.pk):
                # write dummy data
                bf.write_data(var.name,_cast_value([0]*len(timevalues),validate_value_class(value_class)),\
                id = var.pk,\
                description=var.description,\
                value_class = validate_value_class(value_class),\
                unit = udunit)
                continue

            # data[var.pk][::][time,value]
            #out_data = [0]*len(timevalues) # init output data
            out_data = np.zeros(len(timevalues))
            # i                            # time data index
            ii = 0  # source data index
            # calulate mean values
            last_value = None
            max_ii = len(data[var.pk]) - 1
            for i in xrange(len(timevalues)):  # iter over time values

                if ii >= max_ii + 1:
                    # if not more data in data source break
                    if last_value is not None:
                        out_data[i] = last_value
                        continue
                # init mean value vars
                tmp = 0.0  #  sum
                tmp_i = 0.0  #  count

                if data[var.pk][ii][0] < timevalues[i]:
                    # skip elements that are befor current time step
                    while data[var.pk][ii][0] < timevalues[i] and ii < max_ii:
                        last_value = data[var.pk][ii][1]
                        ii += 1

                if ii >= max_ii:
                    if last_value is not None:
                        out_data[i] = last_value
                        continue
                # calc mean value
                if data[var.pk][ii][0] >= timevalues[i] and data[
                        var.pk][ii][0] < timevalues[i] + mean_value_period:
                    # there is data in time range
                    while data[var.pk][ii][0] >= timevalues[i] and data[
                            var.pk][ii][0] < timevalues[
                                i] + mean_value_period and ii < max_ii:
                        # calulate mean value
                        if no_mean_value:
                            tmp = data[var.pk][ii][1]
                            tmp_i = 1
                        else:
                            tmp += data[var.pk][ii][1]
                            tmp_i += 1

                        last_value = data[var.pk][ii][1]
                        ii += 1
                    # calc and store mean value
                    if tmp_i > 0:
                        out_data[i] = tmp / tmp_i
                    else:
                        out_data[i] = data[var.pk][ii][1]
                        last_value = data[var.pk][ii][1]
                else:
                    # there is no data in time range, keep last value, not mean value
                    if last_value is not None:
                        out_data[i] = last_value

            # write data
            bf.write_data(var.name,_cast_value(out_data,validate_value_class(value_class)),\
            id = var.pk,\
            description=var.description,\
            value_class = validate_value_class(value_class),\
            unit = udunit)

    bf.close_file()
    tp.timestamp = time()
    tp.message = 'done'
    tp.progress = tp.max
    tp.done = 1
    tp.save()
Beispiel #2
0
def export_recordeddata_to_file(time_min=None, time_max=None, filename=None, active_vars=None, file_extension=None,
                                append_to_file=False, no_mean_value=False, mean_value_period=5.0,
                                backgroundprocess_id=None, export_task_id=None, **kwargs):
    """
    read all data
    """
    if backgroundprocess_id is not None:
        tp = BackgroundProcess.objects.get(id=backgroundprocess_id)
        tp.message = 'init'
        tp.last_update = now()
        tp.save()
    else:
        tp = None

    if isinstance(time_max, string_types):
        # convert date strings
        time_max = mktime(datetime.strptime(time_max, "%d-%b-%Y %H:%M:%S").timetuple())
    if isinstance(time_min, string_types):
        # convert date strings
        time_min = mktime(datetime.strptime(time_min, "%d-%b-%Y %H:%M:%S").timetuple())

    # add default time_min
    if time_max is None:
        time_max = time()  # now
    if time_min is None:
        time_min = time() - 24 * 60 * 60  # last 24 hours

    # add default extension if no extension is given
    if file_extension is None and filename is None:
        file_extension = '.h5'
    elif filename is not None:
        file_extension = '.' + filename.split('.')[-1]
    # validate file type
    if file_extension not in ['.h5', '.mat', '.csv']:
        if tp is not None:
            tp.last_update = now()
            tp.message = 'failed wrong file type'
            tp.failed = 1
            tp.save()
        return

    # 
    if filename is None:
        if hasattr(settings, 'PYSCADA_EXPORT'):
            if 'output_folder' in settings.PYSCADA_EXPORT:
                backup_file_path = os.path.expanduser(settings.PYSCADA_EXPORT['output_folder'])
            else:
                backup_file_path = os.path.expanduser('~/measurement_data_dumps')
        else:
            backup_file_path = os.path.expanduser('~/measurement_data_dumps')

        # add filename prefix
        backup_file_name = 'measurement_data'
        if hasattr(settings, 'PYSCADA_EXPORT'):
            if 'file_prefix' in settings.PYSCADA_EXPORT:
                backup_file_name = settings.PYSCADA_EXPORT['file_prefix'] + backup_file_name
        # create output dir if not existing
        if not os.path.exists(backup_file_path):
            os.mkdir(backup_file_path)

        # validate time values
        db_time_min = RecordedData.objects.first()  # todo add RecordedDataOld
        if not db_time_min:
            if tp is not None:
                tp.last_update = now()
                tp.message = 'no data to export'
                tp.failed = 1
                tp.save()
            return
        time_min = max(db_time_min.time_value(), time_min)

        db_time_max = RecordedData.objects.last()  # todo add RecordedDataOld
        if not db_time_max:
            if tp is not None:
                tp.last_update = now()
                tp.message = 'no data to export'
                tp.failed = 1
                tp.save()
            return
        time_max = min(db_time_max.time_value(), time_max)

        # filename  and suffix
        cdstr_from = datetime.fromtimestamp(time_min).strftime("%Y_%m_%d_%H%M")
        cdstr_to = datetime.fromtimestamp(time_max).strftime("%Y_%m_%d_%H%M")

        if 'filename_suffix' in kwargs:
            filename = os.path.join(backup_file_path,
                                    backup_file_name + '_' + cdstr_from + '_' + cdstr_to + '_' + kwargs[
                                        'filename_suffix'])
        else:
            filename = os.path.join(backup_file_path, backup_file_name + '_' + cdstr_from + '_' + cdstr_to)

    # check if file exists
    if os.path.exists(filename + file_extension) and not append_to_file:
        count = 0
        filename_old = filename
        while os.path.exists(filename + file_extension):
            filename = filename_old + '_%03.0f' % count
            count += 1

    # append the extension 
    filename = filename + file_extension

    # add Filename to ExportTask
    if export_task_id is not None:
        job = ExportTask.objects.filter(pk=export_task_id).first()
        if job:
            job.filename = filename
            job.save()

    # 
    if active_vars is None:
        active_vars = Variable.objects.filter(active=1, device__active=1)
    else:
        if type(active_vars) is str:
            if active_vars == 'all':
                active_vars = Variable.objects.all()
            else:
                active_vars = Variable.objects.filter(active=1, device__active=1)
        else:
            active_vars = Variable.objects.filter(pk__in=active_vars, active=1, device__active=1)

    if mean_value_period == 0:
        no_mean_value = True
        mean_value_period = 5.0  # todo get from DB, default is 5 seconds

    # calculate time vector

    timevalues = arange(math.ceil(time_min / mean_value_period) * mean_value_period,
                        math.floor(time_max / mean_value_period) * mean_value_period, mean_value_period)

    # get Meta from Settings
    if hasattr(settings, 'PYSCADA_META'):
        if 'description' in settings.PYSCADA_META:
            description = settings.PYSCADA_META['description']
        else:
            description = 'None'
        if 'name' in settings.PYSCADA_META:
            name = settings.PYSCADA_META['name']
        else:
            name = 'None'
    else:
        description = 'None'
        name = 'None'

    if file_extension in ['.h5', '.mat']:
        bf = MatCompatibleH5(filename, version='1.1', description=description, name=name,
                             creation_date=strftime('%d-%b-%Y %H:%M:%S'))
        out_timevalues = [unix_time_stamp_to_matlab_datenum(element) for element in timevalues]
    elif file_extension in ['.csv']:
        bf = ExcelCompatibleCSV(filename, version='1.1', description=description, name=name,
                                creation_date=strftime('%d-%b-%Y %H:%M:%S'))
        out_timevalues = [unix_time_stamp_to_excel_datenum(element) for element in timevalues]
    else:
        return

    # less than 24
    # read everything
    bf.write_data('time', float64(out_timevalues),
                  id=0,
                  description="global time vector",
                  value_class=validate_value_class('FLOAT64'),
                  unit="Days since 0000-1-1 00:00:00",
                  color='#000000',
                  short_name='time',
                  chart_line_thickness=3
                  )

    for var_idx in range(0, active_vars.count(), 10):
        if tp is not None:
            tp.last_update = now()
            tp.message = 'reading values from database (%d)' % var_idx
            tp.save()
        # query data
        var_slice = active_vars[var_idx:var_idx + 10]
        data = RecordedData.objects.get_values_in_time_range(
            variable_id__in=list(var_slice.values_list('pk', flat=True)),
            time_min=time_min,
            time_max=time_max,
            query_first_value=True)

        for var in var_slice:
            # write background task info
            if tp is not None:
                tp.last_update = now()
                tp.message = 'writing values for %s (%d) to file' % (var.name, var.pk)
                tp.save()
            # check if variable is scalled 
            if var.scaling is None or var.value_class.upper() in ['BOOL', 'BOOLEAN']:
                value_class = var.value_class
            else:
                value_class = 'FLOAT64'
            # read unit 
            if hasattr(var.unit, 'udunit'):
                udunit = var.unit.udunit
            else:
                udunit = 'None'

            if var.pk not in data:
                # write dummy data
                bf.write_data(var.name, _cast_value([0] * len(timevalues), validate_value_class(value_class)),
                              id=var.pk,
                              description=var.description,
                              value_class=validate_value_class(value_class),
                              unit=udunit,
                              color=var.chart_line_color_code(),
                              short_name=var.short_name,
                              chart_line_thickness=var.chart_line_thickness)
                continue

            out_data = np.zeros(len(timevalues))
            # i                            # time data index
            ii = 0  # source data index
            # calculate mean values
            last_value = None
            max_ii = len(data[var.pk]) - 1
            for i in range(len(timevalues)):  # iter over time values

                if ii >= max_ii + 1:
                    # if not more data in data source break
                    if last_value is not None:
                        out_data[i] = last_value
                        continue
                # init mean value vars
                tmp = 0.0  # sum
                tmp_i = 0.0  # count

                if data[var.pk][ii][0] < timevalues[i]:
                    # skip elements that are befor current time step
                    while data[var.pk][ii][0] < timevalues[i] and ii < max_ii:
                        last_value = data[var.pk][ii][1]
                        ii += 1

                if ii >= max_ii:
                    if last_value is not None:
                        out_data[i] = last_value
                        continue
                # calc mean value
                if timevalues[i] <= data[var.pk][ii][0] < timevalues[i] + mean_value_period:
                    # there is data in time range
                    while timevalues[i] <= data[var.pk][ii][0] < timevalues[i] + mean_value_period and ii < max_ii:
                        # calculate mean value
                        if no_mean_value:
                            tmp = data[var.pk][ii][1]
                            tmp_i = 1
                        else:
                            tmp += data[var.pk][ii][1]
                            tmp_i += 1

                        last_value = data[var.pk][ii][1]
                        ii += 1
                    # calc and store mean value
                    if tmp_i > 0:
                        out_data[i] = tmp / tmp_i
                    else:
                        out_data[i] = data[var.pk][ii][1]
                        last_value = data[var.pk][ii][1]
                else:
                    # there is no data in time range, keep last value, not mean value
                    if last_value is not None:
                        out_data[i] = last_value

            # write data
            bf.write_data(var.name, _cast_value(out_data, validate_value_class(value_class)),
                          id=var.pk,
                          description=var.description,
                          value_class=validate_value_class(value_class),
                          unit=udunit,
                          color=var.chart_line_color_code(),
                          short_name=var.short_name,
                          chart_line_thickness=var.chart_line_thickness)

    bf.close_file()
    if tp is not None:
        tp.last_update = now()
        tp.message = 'done'
        tp.done = True
        tp.save()