# 版本号
version: 1.0
protocol:
  # 协议标识【必填】内置协议不允许修改，匹配协议
  name:  "52"
  # 协议显示名称【必填】内置协议不允许修改
  display_name: "三河室温采集数据对接(泰德尔v1)"
  # 协议说明
  content: "三河室温采集数据对接(泰德尔v1)"
  # 支持的通讯类型，可多选，英文逗号分割，默认五种都支持
  # 共 5 个（多选）：1 - 直连设备, 2 - 网关设备, 3 - 网关子设备, 4 - 普通设备, 5 - 组合设备
  device_types:
    - 1
    - 2
    - 3
  # 技术参数（有则以下必填校验生效）
  # rule 规则类型：
  # REGEX：正则表达式校验
  # REGEX：正则表达式校验
  # FOR_MQTT：从 mqtt 获取
  # ENUM：枚举值校验
  # RANGE：范围校验
  # NONE：无校验
  attributes:
    # 技术参数名称【必填】
    - name: "SN"
      # 技术参数说明
      content: "字符串，智能体设备标识"
      # 技术参数值是否可编辑，默认 false
      value_editable: true
      # 默认值
      default_value:
      # 是否通用技术参数，默认 false
      generic: true
      # 是否必填，默认 false
      required: false
      # 单位
      unit:
      # 技术参数规则类型【必填】
      rule: NONE
      # 技术参数规则内容【必填】
      # RULE 是 REGEX、ENUM、RANGE 时，rule_content 必填
      rule_content:
    - name: "intelligentDeviceFlag"
      content: "是否是智能体设备"
      value_editable: true
      default_value:
      generic: true
      required: false
      unit:
      rule: ENUM
      rule_content:
        enum:
          - true
          - false
    - name: "intelligentGatewayFlag"
      content: "是否是智能体网关"
      value_editable: true
      default_value:
      generic: true
      required: false
      unit:
      rule: ENUM
      rule_content:
        enum:
          - true
          - false
    - name: "edgeLinkUrl"
      content: "边缘侧的连接地址"
      value_editable: true
      default_value:
      generic: true
      required: false
      unit:
      rule: REGEX
      rule_content:
        regex: "^(https?://).*"
  # 控制脚本【必填】
  # 目前所有支持的变量参考 「设备类详情」-「控制配置」-「info图标」
  control_script: |
    ## 帮助文档实例：
    control:
      ## carrier：描述使用的载体方式（目前支持MQTT、http方式的下发，通过carrier进行字段配置。)【必填】
      - carrier: "mqtt"
        ## foreign：在使用MQTT时的定制描述，是否使用外部载体。【必填】
        foreign: true
        ## async：控制是否是异步操作。【必填】
        async: true
        ## propertyName：对应的属性字段，若不填写则为通配。通配作为最低优先级，优先单个配置。【非必填】
        propertyName: "test_01"
        ## 使用外部载体时，需配置MQTT broker的地址。【使用外部载体必填】
        server: "${MQTT_SERVER}"
        ## 使用外部载体时，需配置连接MQTT broker传输的协议版本（目前暂时仅支持3.1.1，可使用$MQTT_PROTOCOL填写代替）。【使用外部载体必填】
        protocol: "${MQTT_PROTOCOL}"
        ## 使用外部载体时，需配置信息传达的目标topic【使用外部载体必填】
        topic: "down/device/208/7Qr4d3iqlX/1"
        ## qos：使用外部载体时，需配置传达到的目标的ack方式（平台默认0，可使用$MQTT_QOS填写代替）【使用外部载体必填】
        qos: ${MQTT_QOS}
        ## 使用外部载体时，需配置使用连接MQTT broker的clientId【使用外部载体必填】
        clientId: "84812"
        ## 使用外部载体时，需配置使用连接MQTT broker的账号【使用外部载体必填】
        username: "gev9oTcwKd@监听设备"
        ## 使用外部载体时，需配置使用连接MQTT broker的密码【使用外部载体必填】
        password: "779e7ed8e3c0404f8f80a839eba9d402"
        ## timeout：该点位控制的超时时间，从实际下发开始。可填占位符后端默认15s【必填】
        timeout: ${TIMEOUT}
        ## body：作为MQTT载体中主要携带的信息。【必填】
        body: "{\"id\":${LOWER_CONTROL_ID},\"deviceId\": \"modbus\",\"data\":{\"wendu\":${TARGET_VALUE}}\"}"
        ## propertyMap：mqtt v5 协议新特性  property  以下propertyMap配置为边缘 需接受的模板
        propertyMap:
          userId: ${userId}
          deviceName: ${device.name}
          propertyName: ${tslProperty.name}
          targetValue: ${TARGET_VALUE}
          async: ${async?c}
        callback:
          ## 描述回调时信息中所携带控制字段名，通过"."的方式描述字段的层级，例如：a.b.c描述为a对象，下的b对象，下的c字段。【异步必填】
          controlIdField: "id"
          ## 使用外部载体时，描述回调时监听信息返回的通道。【异步且使用外部载体时必填】
          topic: "up/callback/device/208/7Qr4d3iqlX/1"
          ## 描述回调时信息的成功字符包含条件。【异步必填】
          payload: "success"
        ## 控制是否是异步操作。【必填】
      - async: true
        ##【carrier：描述使用的载体方式（目前支持MQTT、http方式的下发，通过carrier进行字段配置。)【必填】
        carrier: "http"
        ## propertyName：对应的属性字段，若不填写则为通配。通配作为最低优先级，优先单个配置。【非必填】
        propertyName: "test_01"
        ## url：控制的http地址【必填】
        url: "http://1.116.134.81:8088/control"
        ## method：控制的http方式（目前仅支持post、get）【必填】
        method: "post"
        ## headers：控制的http请求头参数，该项为不定扩展项，map的形式key作为请求头参数的key，value作为请求头参数需要的值。
        headers:
          tenantId: ${tenantId}
          deviceTemplateId: ${deviceTemplate.id}
          cjq: ${attribute.cjq}
        ## body：使用post请求时需描述的参数。
        body: "{\"target\":\"${TARGET_VALUE}\"}"
        ## timeout：该点位控制的超时时间，从实际下发开始。可填占位符后端默认15s【必填】
        timeout: 15000
        ## successStatusCodes：作为http响应成功的认定条件之状态码，发起控制时，判断信息是否成功的条件之一，满足列表项之一即可，但需与successResponseBody同时成立。
        ## successResponseBody：作为http响应成功的认定条件之字符包含，发起控制时，判断信息是否成功的条件之一，满足列表项之一即可，但需与successStatusCodes同时成立。
        successStatusCodes:
          - 200
          - 204
        successResponseBody:
          - "成功"
        callback:
          ## 描述回调时信息的成功字符包含条件。【异步必填】
          payload: "success"
          ## 描述回调时信息中所携带控制字段名，通过"."的方式描述字段的层级，例如：a.b.c描述为a对象，下的b对象，下的c字段。【异步必填】
          controlIdField: "id"
  # 采集脚本【必填】
  # 目前所有支持的变量参考 「设备类详情」-「脚本」-「info图标」
  telegraf_scripts:
    # 脚本名称【必填】
    - name: "输入"
      # 脚本排序（执行顺序）【必填】
      # 需要与脚本中order保持一致，其中输入脚本order固定为0，输出脚本固定为10000
      order: 0
      # 脚本类型，单选【必填】
      # 参考文档 http://mrdoc.iheatingos.com/doc/11588#function_type
      function_type: 1
      # telegraf 类型，多选【必填】
      # 参考文档 http://mrdoc.iheatingos.com/doc/11588#telegraf_type
      telegraf_types:
        - 1
      # 数据存储版本，默认 V1
      # 共两个版本：V1 - 默认, V2 - 新增对数据表字段类型不一致问题处理
      data_storage_version: V1
      content: |
        [[inputs.http]]
          interval = "5s" #采集间隔时长
          timeout = "100s"
          precision = "1s"
          collection_jitter = "20s"
          name_override = "${TEMPLATE_NAME}"
          urls = [
            <#assign parts = DEVICE_NAME_LIST_WITH_CHARACTER?split(',')>
            <#list parts as part>
                <#assign device_name = part?remove_beginning('\\"')?remove_ending('\\"')>
                "http://nodered-service.dev.svc.cluster.local:1880/get/data/device?device_name=${device_name}"<#if part?has_next>,</#if>
            </#list>
          ]
          method = "GET"
          data_format = "json"
          json_query = "data"
          json_string_fields = ["*"]
          tag_keys = ["device_name"] 
    - name: "设备名称匹配"
      order: 55
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.enum]]
            namepass= ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}${DEVICE_TYPE}@marking"
            order = ${order@55}
            [[processors.enum.mapping]]
                tag = "device_name"
                dest ="device_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_NAME_TO_DEVICE_ID_MAP}
    - name: "改名"
      order: 60
      function_type: 8
      telegraf_types:
        - 1
        - 2
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@forward.metric_name_to_device_template_modifier"
            order = ${order@60}
            source = '''
        def apply(metric):
            map={${DEVICE_ID_TEMPLATE_NAME_MAP}}
            if 'device_id' in metric.tags.keys() and metric.tags["device_id"] in map:
                name=map[metric.tags["device_id"]]+"${DEVICE_TYPE}"
                metric.name=name
            return metric
        '''
    - name: "复用"
      order: 70
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@reuse.device_reuse"
            order = ${order@70}
            source = '''
        def apply(metric):
            toReuseDevices = {${DEVICE_ID_TO_REUSE_DEVICE_ID}}
            deviceIdToTemplateNames = {${REUSE_DEVICE_ID_TO_TEMPLATE_NAME}}
            metrics = []
            metrics.append(metric)
            if "device_id" in metric.tags.keys() and metric.tags["device_id"] in toReuseDevices:
              deviceIds = toReuseDevices[metric.tags["device_id"]]
              for deviceId in deviceIds:
                if deviceId in deviceIdToTemplateNames:
                  templateName = deviceIdToTemplateNames[deviceId]
                  newMetric = deepcopy(metric)
                  newMetric.name = templateName
                  newMetric.tags["device_id"] = deviceId
                  metrics.append(newMetric)
            return metrics
        '''
    - name: "复用"
      order: 80
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@reuse.property_reuse"
            order = ${order@80}
            source = '''
        def apply(metric):
            toReusePropertys = [${REUSE_PROPERTY}]
            for toReuseProperty in toReusePropertys:
              start = toReuseProperty.find("&{")
              end = toReuseProperty.rfind("}")
              if start == -1 or end == -1 or start >= end:
                continue
              property =  toReuseProperty[start + 2:end]
              if property in metric.fields:
                metric.fields[toReuseProperty] = metric.fields[property]
            return metric
        '''
    - name: "打标"
      order: 200
      function_type: 2
      telegraf_types:
        - 1
        - 2
      data_storage_version: V1
      content: |
        [[processors.enum]]
            namepass= ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@marking.id_to_info"
            order = ${order@200}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="device_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_DEVICE_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="organization_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_ORGANZATION_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="space_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_SPACE_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="tenant_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TENANT_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="device_standard_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_DEVICE_STANDARD_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_standard_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_STANDARD_NAME_MAP}
    - name: "转发"
      order: 300
      function_type: 7
      telegraf_types:
        - 2
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass=["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@forward.gateway"
            order = ${order@300}
            source = '''
        def apply(metric):
            if 'device_id' in metric.tags.keys() and 'template_name' in metric.tags.keys() and 'device_name' in metric.tags.keys() and 'tenant_id' in metric.tags.keys():
                metric.name = 'up/device/'+metric.tags["tenant_id"]+'/'+metric.tags["template_name"] + '/' + metric.tags["device_name"]
                device_id=metric.tags.get("device_id")
                metric.tags.clear()
                metric.tags.setdefault("device_id",device_id)
            return metric
        '''
    - name: "改名"
      order: 400
      function_type: 8
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.rename]]
            namepass = ["${TEMPLATE_NAME}"]
            alias = "${TEMPLATE_NAME}@rename.name_to_standard_name"
            order = ${order@400}
                ${RENAME_LIST}
    - name: "打标"
      order: 850
      function_type: 2
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}"]
            alias = "${TEMPLATE_NAME}@marking.bool_to_num"
            order = ${order@850}
            source = '''
        def apply(metric):
            boolFields = [${BOOL_FIELDS}]
            for boolField in boolFields:
                if boolField in metric.fields:
                    value = metric.fields[boolField]
                    value = str(value)
                    value = value.replace(" ", "")
                    value = value.lower()
                    if value == "true":
                        metric.fields[boolField] = 1
                    if value == "false":
                        metric.fields[boolField] = 0
            return metric
        '''
    - name: "计算"
      order: 900
      function_type: 5
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}"]
            alias = "${TEMPLATE_NAME}@calculate.calculate_property"
            order = ${order@900}
            source = '''
        def apply(metric):
            ${CALCULATE_PROPERTY_LIST}
            return metric
        '''
    - name: "字段类型转换"
      order: 950
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V2
      content: |
        [[processors.converter]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@convert.data_type"
            order = ${order@950}
            [processors.converter.fields]
                integer = [${INTEGER_AND_BOOL_FIELD_STANDARD_NAMES}]
                float = [${FLOAT_FIELD_STANDARD_NAMES}]
                string = [${STRING_AND_TIME_FIELD_STANDARD_NAMES}]
    - name: "复制"
      order: 1000
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@copy.placeholder_disassemble"
            fieldpass =[${PROPERT_SET}]
            order = ${order@1000}
            source = '''
        def apply(metric):
            metrics = []
            map = {}
            initMetric = Metric(metric.name)
            for tag in metric.tags:
                initMetric.tags[tag] = metric.tags[tag]
            initMetric.time = metric.time
            for field in metric.fields:
                if "@" in field:
                    propertyName = field
                    deviceStandardName = field[field.rfind("@")+1:]
                    if deviceStandardName not in map:
                        map[deviceStandardName] = {propertyName:metric.fields[field]}
                    else:
                        map[deviceStandardName][propertyName] = metric.fields[field]
                    continue
                initMetric.fields[field] = metric.fields[field]
            metrics.append(initMetric)
            for k,v in map.items():
                if k != '':
                    newMetric = Metric(metric.name)
                    newMetric.time=metric.time
                    for tag in metric.tags.keys():
                        if tag == "device_id" or tag == "device_name" or tag == "organization_id" or tag == "space_id":
                            continue
                        newMetric.tags[tag] = metric.tags[tag]
                    newMetric.tags["device_standard_name"] = k
                    for k1,v1 in v.items():
                        newMetric.fields[k1] = v1
                    metrics.append(newMetric)
            return metrics
        '''
    - name: "复制"
      order: 1050
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@copy.copy_to_standard"
            order = ${order@1050}
            source = '''
        def apply(metric):
            templateStandardName = "${TEMPLATE_STANDARD_NAME}"
            tenantId = "${TENANT_ID}"
            templateId = "${TEMPLATE_ID}"
            templateName = "${TEMPLATE_NAME}"
            metrics = []
            metrics.append(metric)
            if "template_standard_name" in metric.tags.keys():
               templateStandardName = metric.tags["template_standard_name"]
            newMetric = Metric(metric.name + "@" + templateStandardName)
            newMetric.time=metric.time
            newMetric.tags["template_standard_name"] = templateStandardName
            newMetric.tags["tenant_id"] = tenantId
            newMetric.tags["template_id"] = templateId
            newMetric.tags["template_name"] = templateName
            for tag in metric.tags.keys():
                newMetric.tags[tag] = metric.tags[tag]
            for field in metric.fields:
                newMetric.fields[field] = metric.fields[field]
            metrics.append(newMetric)
            return metrics
        '''
    - name: "打标"
      order: 1100
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
            alias = "${TEMPLATE_NAME}@marking.standard_name_to_id"
            order = ${order@1100}
            source = '''
        def apply(metric):
            standardNameToIdMap={${DEVICE_STANDARD_NAME_TO_DEVICE_ID_ARR_MAP}}
            metrics = []
            if "device_id" not in metric.tags.keys() and "device_standard_name" in metric.tags.keys():
                deviceStandardName = metric.tags["device_standard_name"]
                if deviceStandardName in standardNameToIdMap:
                    deviceIdArr = standardNameToIdMap[deviceStandardName]
                    for deviceId in deviceIdArr:
                        newMetric = Metric(metric.name)
                        newMetric.time=metric.time
                        for tag in metric.tags.keys():
                            newMetric.tags[tag] = metric.tags[tag]
                        newMetric.tags["device_id"] = str(deviceId)
                        for field in metric.fields:
                            newMetric.fields[field] = metric.fields[field]
                        metrics.append(newMetric)
            else:
               metrics.append(metric)
            return metrics
        '''
    - name: "打标"
      order: 1150
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@marking.standard_name_to_id"
            order = ${order@1150}
            source = '''
        def apply(metric):
            map = {${DEVICE_STANDARD_NAME_TO_DEVICE_ID_ARR_MAP}}
            if "device_id" not in metric.tags.keys() and "device_standard_name" in metric.tags.keys():
                if metric.tags["device_standard_name"] in map:
                    deviceIdArr = map[metric.tags["device_standard_name"]]
                    if len(deviceIdArr) == 1:
                        metric.tags["device_id"] = str(deviceIdArr[0])
            return metric
        '''
    - name: "打标"
      order: 1200
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.enum]]
            namepass= ["${TEMPLATE_NAME}${DEVICE_TYPE}","${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@marking.id_to_info_repeat"
            order = ${order@1200}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="device_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_DEVICE_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="organization_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_ORGANZATION_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="space_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_SPACE_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="tenant_id"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TENANT_ID_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="device_standard_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_DEVICE_STANDARD_NAME_MAP}
            [[processors.enum.mapping]]
                tag = "device_id"
                dest ="template_standard_name"
                [processors.enum.mapping.value_mappings]
                    ${DEVICE_ID_TO_TEMPLATE_STANDARD_NAME_MAP}
    - name: "补点"
      order: 1250
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@supplement.time_supplement"
            order = ${order@1250}
            source = '''
        load("time.star", "time")
        def apply(metric):
            if "tenant_id" not in metric.tags.keys():
                return None
            if "template_standard_name" not in metric.tags.keys() or metric.tags["template_standard_name"] == "":
                return None
            if "device_standard_name" not in metric.tags.keys() or metric.tags["device_standard_name"] == "":
                return None
            map = {${PROPERTY_TO_TIME_PATTERN}}
            propertyTimeMap = {}
            maxTime = None
            lackTimeNames = []
            newMetric = Metric(metric.name)
            for tag in metric.tags.keys():
                newMetric.tags[tag] = metric.tags[tag]
            newMetric.time = metric.time
            for field in metric.fields:
                if field not in map:
                    newMetric.fields[field] = metric.fields[field]
                    continue
                if metric.fields[field] == 0 or metric.fields[field] == "" or metric.fields[field] == "0":
                    continue
                if map[field] != "":
                    timeFormat = map[field]
                else:
                    timeFormat = "unix_ms"
                propertyTime = None
                if timeFormat == "unix":
                    propertyTime = time.from_timestamp(int(metric.fields[field])).unix_nano/1e6
                elif timeFormat == "unix_ms":
                    propertyTime = time.from_timestamp(int(int(metric.fields[field]) / 1e3),int((int(metric.fields[field]) * 1e6 % 1e9))).unix_nano/1e6
                else:
                    propertyTime = time.parse_time(str(metric.fields[field]), format=timeFormat, location = "Asia/Shanghai").unix_nano/1e6
                newMetric.fields[field] = propertyTime

            for field in newMetric.fields:
                propertyName = field
                realPropertyName = field
                if "@" in propertyName:
                    realPropertyName = propertyName[:propertyName.rfind("@")]
                    propertyName = propertyName[:propertyName.rfind("@")]+"_time@"+propertyName[propertyName.rfind("@")+1:]
                else:
                    propertyName = propertyName + "_time"
                if realPropertyName.endswith("_time"):
                    continue
                if propertyName in newMetric.fields:
                    if maxTime == None or maxTime < newMetric.fields[propertyName]*1e6:
                        maxTime = newMetric.fields[propertyName]*1e6
                else:
                    lackTimeNames.append(propertyName)
            if maxTime == None:
                maxTime = newMetric.time
            else:
                newMetric.time = int(maxTime)
            for propertyName in lackTimeNames:
               newMetric.fields[propertyName] = int(maxTime/1e6)
            return newMetric
        '''
    - name: "改名"
      order: 1300
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@rename.remove_standard_name"
            fieldpass =[${NEW_UPPER_PUSH_ENABLE_PROPERTY_STANDARD_NAME_LIST}]
            order = ${order@1300}
            source = '''
        def apply(metric):
            newMetric = Metric(metric.name)
            for tag in metric.tags.keys():
                newMetric.tags[tag] = metric.tags[tag]
            newMetric.time = metric.time
            for field in metric.fields:
                if "@"+metric.tags["device_standard_name"] in field:
                    newField = field.replace("@"+metric.tags["device_standard_name"],"")
                    newMetric.fields[newField] = metric.fields[field]
                else:
                    newMetric.fields[field] = metric.fields[field]
            return newMetric
        '''
    - name: "改名"
      order: 1350
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@rename.replace_placeholders"
            order = ${order@1350}
            source = '''
        def apply(metric):
            map = {${DEVICE_ATTRIBUTE}}
            if "device_id" not in metric.tags.keys() or metric.tags["device_id"] not in map:
                return metric
            newMetric = Metric(metric.name)
            for tag in metric.tags.keys():
                newMetric.tags[tag] = metric.tags[tag]
            newMetric.time = metric.time
            for field in metric.fields:
                attributeMap = map[metric.tags["device_id"]]
                newField = field
                for k,v in attributeMap.items():
                    if "{"+k+"}" in field:
                        newField = newField.replace("{"+k+"}",v)
                newMetric.fields[newField] = metric.fields[field]
            return newMetric
        '''
    - name: "转发"
      order: 1400
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
            namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}@${TEMPLATE_STANDARD_NAME}"]
            alias = "${TEMPLATE_NAME}@forward.metric_name_to_standard_name"
            order = ${order@1400}
            source = '''
        def apply(metric):
            if metric.tags["template_name"]+"@" in metric.name:
                metric.name = metric.name.replace(metric.tags["template_name"]+"@","")
            return metric
        '''
    - name: "通用补时间"
      order: 1450
      function_type: 11
      telegraf_types:
        - 1
      data_storage_version: V1
      content: |
        [[processors.starlark]]
          namepass = ["${TEMPLATE_NAME}${DEVICE_TYPE}"]
          alias = "${TEMPLATE_NAME}@supplement.common_time_supplement"
          order = ${order@1450}
          source = '''
        def apply(metric):
            enable = "${COMMON_TIME_SUPPLEMENT_ENABLE}"
            if enable == "false":
                return metric
            fields = metric.fields
            for field in list(fields.keys()):
                base = field
                suffix = ""
                if "@" in field:
                    at = field.rfind("@")
                    base = field[:at]
                    suffix = field[at:]
                if base.endswith("_time"):
                    continue
                time_field = base + "_time" + suffix
                if time_field not in fields:
                    fields[time_field] = int(metric.time // 1000000)
            return metric
        '''