/*
  Сервис реализует функционал управления приборами учёта(ПУ)
*/
syntax = "proto3";

import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/wrappers.proto";
import "google/protobuf/timestamp.proto";
import "google/api/visibility.proto";

package keyapis.telemetry_control.v1;

option java_package = "ru.keyapis.telemetry_control.v1";
option java_outer_classname = "KeyapisTelemetryControlV1Proto";
option java_multiple_files = false;
option java_string_check_utf8 = true;
option go_package = "/keyapis_telemetry_control_v1";
option cc_enable_arenas = true;
option csharp_namespace = "Keyapis.TelemetryControl.V1";
option objc_class_prefix = "KEYAPISTELEMETRYCONTROLV1";
option php_namespace = "Keyapis\\TelemetryControl\\V1";
option ruby_package = "Keyapis::TelemetryControl::V1";
option optimize_for = LITE_RUNTIME;

// Сервис приборов учёта (ПУ).
// Авторизация:
//   - Authorization: Bearer token.
//   - X-Api-Key: apiKey
service DeviceService {
  // Полнодуплексный метод отправки команд на сервер и получения изменения со стороны сервера.
  // Разрешения: telemetry_control:device:list, telemetry_control:device:list:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. При наличии разрешений.
  // Метод доступен для: ApiKey: Без учета разрешений
  rpc PostDeviceFullDuplex(stream PostDeviceFullDuplexRequest) returns (stream PostDeviceFullDuplexResponse) {}
  // Метод получения ПУ.
  // Разрешения: telemetry_control:device:card, telemetry_control:device:card:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee, master. При наличии разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDevice(GetDeviceRequest) returns (GetDeviceResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/{id}"
    };
  }
  // Метод получения списка приборов учета.
  // Разрешения: telemetry_control:device:list, telemetry_control:device:list:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee, master. При наличии разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceList(GetDeviceListRequest) returns (stream GetDeviceListResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/list"
    };
  }
  // Метод получения количества приборов учета.
  // Разрешения: telemetry_control:device:list, telemetry_control:device:list:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee, master. При наличии разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceCount(GetDeviceCountRequest) returns (GetDeviceCountResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/count"
    };
  }
  // Метод замены прибора учета.
  // Создает ПУ и привязывает его индикаторы к ТУ исходного ПУ.
  // Разрешения: telemetry_control:device:save, telemetry_control:device:save:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. При наличии разрешений
  rpc PostDeviceReplace(PostDeviceReplaceRequest) returns (PostDeviceReplaceResponse) {
    option (google.api.http) = {
      post: "/telemetry_control/api/v1/device/replace"
      body: "*"
    };
  }
  // Метод сохранения прибора учета.
  // Поддерживает создание и обновление.
  // Разрешения: telemetry_control:device:save, telemetry_control:device:save:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. При наличии разрешений
  rpc PostDevice(PostDeviceRequest) returns (PostDeviceResponse) {
    option (google.api.http) = {
      post: "/telemetry_control/api/v1/device"
      body: "*"
    };
  }
  // Метод удаления прибора учета.
  // Разрешения: telemetry_control:device:remove, telemetry_control:device:remove:own.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. При наличии разрешений
  rpc DeleteDevice(DeleteDeviceRequest) returns (DeleteDeviceResponse) {
    option (google.api.http) = {
      delete: "/telemetry_control/api/v1/device/{id}"
    };
  }
  // Метод сохранения индикатора.
  // Поддерживает создание и обновление.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений
  rpc PostDeviceIndicator(PostDeviceIndicatorRequest) returns (PostDeviceIndicatorResponse) {
    option (google.api.http) = {
      post: "/telemetry_control/api/v1/device/indicator"
      body: "*"
    };
  }
  // Метод получения индикатора.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceIndicator(GetDeviceIndicatorRequest) returns (GetDeviceIndicatorResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/indicator/{id}"
    };
  }
  // Метод получения списка индикаторов.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceIndicatorList(GetDeviceIndicatorListRequest) returns (stream GetDeviceIndicatorListResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/indicator/list"
    };
  }
  // Метод получения количества индикаторов.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceIndicatorCount(GetDeviceIndicatorCountRequest) returns (GetDeviceIndicatorCountResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/indicator/count"
    };
  }
  // Метод удаления индикаторa.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений
  rpc DeleteDeviceIndicator(DeleteDeviceIndicatorRequest) returns (DeleteDeviceIndicatorResponse) {
    option (google.api.http) = {
      delete: "/telemetry_control/api/v1/device/indicator/{id}"
    };
  }
  // Метод получения списка связей индикаторов и ТУ.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceIndicatorMetricPointList(GetDeviceIndicatorMetricPointListRequest) returns (stream GetDeviceIndicatorMetricPointListResponse) {
      option (google.api.http) = {
          get: "/telemetry_control/api/v1/device/indicator/metric_point/list"
      };
  }
  // Метод получения количества связей индикаторов и ТУ.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений.
  // Метод доступен для: ApiKey: При наличии разрешений
  rpc GetDeviceIndicatorMetricPointCount(GetDeviceIndicatorMetricPointCountRequest) returns (GetDeviceIndicatorMetricPointCountResponse) {
      option (google.api.http) = {
          get: "/telemetry_control/api/v1/device/indicator/metric_point/count"
      };
  }
  // Метод сохранения связи индикаторов и ТУ.
  // Поддерживает только создание связи.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений
  rpc PutDeviceIndicatorMetricPointAttach(PutDeviceIndicatorMetricPointAttachRequest) returns (PutDeviceIndicatorMetricPointAttachResponse) {
    option (google.api.http) = {
      put: "/telemetry_control/api/v1/device/indicator/{device_indicator_metric_point.indicator_id}/metric_point/{device_indicator_metric_point.metric_point_id}/attach"
    };
  }
  // Метод удаления связи индикаторов и ТУ.
  // Метод доступен для: Token: admin, service, bti, seller, application, owner, employee. Без учета разрешений
  rpc PutDeviceIndicatorMetricPointDetach(PutDeviceIndicatorMetricPointDetachRequest) returns (PutDeviceIndicatorMetricPointDetachResponse) {
    option (google.api.http) = {
      put: "/telemetry_control/api/v1/device/indicator/{device_indicator_metric_point.indicator_id}/metric_point/{device_indicator_metric_point.metric_point_id}/detach"
    };
  }
  // Метод получения списка связей ПУ и группы пользователя.
  // Метод доступен для: Token: admin, service, bti, seller. Без учета разрешений
  rpc GetDeviceGroupList(GetDeviceGroupListRequest) returns (stream GetDeviceGroupListResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/group/list"
    };
  }
  // Метод получения количества связей ПУ и группы пользователя.
  // Метод доступен для: Token: admin, service, bti, seller. Без учета разрешений
  rpc GetDeviceGroupCount(GetDeviceGroupCountRequest) returns (GetDeviceGroupCountResponse) {
    option (google.api.http) = {
      get: "/telemetry_control/api/v1/device/group/count"
    };
  }
  // Метод сохранения связей ПУ и группы пользователя.
  // Поддерживает только создание.
  // Метод доступен для: Token: admin, service, bti, seller. Без учета разрешений
  rpc PutDeviceGroupAttach(PutDeviceGroupAttachRequest) returns (PutDeviceGroupAttachResponse) {
    option (google.api.http) = {
      put: "/telemetry_control/api/v1/device/{device_group.device_id}/group/{device_group.group_id}/attach"
    };
  }
  // Метод удаления связей ПУ и группы пользователя.
  // Метод доступен для: Token: admin, service, bti, seller. Без учета разрешений
  rpc PutDeviceGroupDetach(PutDeviceGroupDetachRequest) returns (PutDeviceGroupDetachResponse) {
    option (google.api.http) = {
      put: "/telemetry_control/api/v1/device/{device_group.device_id}/group/{device_group.group_id}/detach"
    };
  }
}

// Запрос удаления прибора учета
message DeleteDeviceRequest {
  // Идентификатор
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос удаления прибора учета
message DeleteDeviceResponse {}

// Запрос сохранения связей ПУ и группы пользователя
message PutDeviceGroupAttachRequest {
  // Связь ПУ и группы пользователя
  DeviceGroup device_group = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос сохранения связи ПУ и группы пользователя
message PutDeviceGroupAttachResponse {}


// Запрос получения списка
message GetDeviceGroupListRequest {
  // Фильтр связей ПУ и группы пользователя
  DeviceGroupFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Пагинация
    DeviceGroupPaging paging = 2;
  }
}

// Пагинация связей ПУ и группы пользователя
message DeviceGroupPaging {
  // Справочник типов сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По Идентификатору группы пользователя
    GROUP_ID = 1;
    // По ПУ
    DEVICE_ID = 2;
  }
  // Тип значения сортировки.
  // По умолчанию: GROUP_ID
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Ответ на запрос получения списка связей ПУ и группы пользователя
message GetDeviceGroupListResponse {
  // Тип результата
  oneof type {
    // Связь ПУ и группы пользователя
    DeviceGroup data = 1;
  }
}

// Запрос получения количества связей ПУ и группы пользователя
message GetDeviceGroupCountRequest {
  // Фильтр связей ПУ и группы пользователя
  DeviceGroupFilter filter = 1;
}

// Фильтр для запроса связей ПУ и группы пользователя.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message DeviceGroupFilter {
  // По Идентификатору группы пользователя
  repeated string group_ids = 1;
  // По ПУ
  repeated int32 device_ids = 2;
}


// Ответ на запрос получения количества связей ПУ и группы пользователя
message GetDeviceGroupCountResponse {
  // Тип результата
  oneof type {
    // Всего связей ПУ и группы пользователя
    int32 data = 1;
  }
}

// Запрос удаления связей ПУ и группы пользователя
message PutDeviceGroupDetachRequest {
  // Связь ПУ и группы пользователя
  DeviceGroup device_group = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос удаления связи ПУ и группы пользователя
message PutDeviceGroupDetachResponse {}

// Связка ПУ и группы пользователя.
// Задает область ресурсов (resource scope), доступную пользователю.
// Используется для контроля доступа к ПУ
message DeviceGroup {
  // Идентификатор группы.
  // # Тип: Guid
  string group_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Идентификатор ПУ.
  // # Диапазон: 0..2147483647
  int32 device_id = 2 [(google.api.field_behavior) = REQUIRED];
}

// Запрос сохранения индикатора
message PostDeviceIndicatorRequest {
  // Индикатор
  Indicator data = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос сохранения индикатора
message PostDeviceIndicatorResponse {
  // Ошибка запроса сохранения индикатора
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      Indicator.ValidationError validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Индикатор
    Indicator data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос получения индикатора
message GetDeviceIndicatorRequest {
  // Идентификатор индикатора
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос получения индикатора
message GetDeviceIndicatorResponse {
  // Тип результата
  oneof type {
    // Индикатор
    Indicator data = 1;
  }
}
// Запрос получения ПУ
message GetDeviceRequest {
  // Идентификатор ПУ
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос получения ПУ
message GetDeviceResponse {
  // Тип результата
  oneof type {
    // Прибор учета
    Device data = 1;
  }
}

// Запрос получения списка
message GetDeviceIndicatorListRequest {
  // Фильтр индикаторов
  IndicatorFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Пагинация по индикаторам
    IndicatorPaging paging = 2;
  }
}

// Пагинация индикаторов
message IndicatorPaging {
  // Ошибка валидации постраничной пагинации по индикаторам.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Причины:
    // - Значение количества < 0 или > 100
    message LimitInvalid {}
    // Причины:
    // - Значение сдвига < 0
    message OffsetInvalid {}

    // Причина ошибки
    oneof reason {
      // Количество передано некорректно
      LimitInvalid limit = 1;
      // Сдвиг передан некорректно
      OffsetInvalid offset = 2;
    }
  }
  // Справочник типов сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По уникальному ключу
    ID = 1;
    // По типу измерений
    SIGN_TYPE = 2;
    // По Прибору учета
    DEVICE_ID = 3;
    // По Дате создания
    CREATED_AT = 4;
  }
  // Тип значения сортировки.
  // По умолчанию: ID
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Ответ на запрос получения списка индикаторов
message GetDeviceIndicatorListResponse {
  // Ошибка запроса получения списка индикаторов
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка фильтрации
      IndicatorFilter.ValidationError device_filter_validation = 1;
      // Ошибка пагинации  по страницам
      IndicatorPaging.ValidationError device_paging_validation = 2;
    }
  }
  // Тип результата
  oneof type {
    // Индикатор
    Indicator data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Фильтр для запроса индикаторов.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message IndicatorFilter {
  // Ошибки валидации.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Путь к полю в формате наименования protobuf
    string path = 1 [(google.api.field_behavior) = REQUIRED];
    // Валидационное сообщение
    string message = 2 [(google.api.field_behavior) = REQUIRED];
  }
  // По списку приборов учета
  repeated int32 device_ids = 1;
  // По типам измерений
  repeated Indicator.SignType sign_types = 2;
  // По списку ключей индикаторов.
  // Устарело, использовать метод GetDeviceIndicator
  repeated int32 ids = 3 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // По серийным номерам привязанных ПУ
  repeated string device_serial_numbers = 4;
  // По идентификаторам объектов строительства, привязанных ТУ
  repeated int32 building_ids = 5;
  // По Номерам помещений, привязанных ТУ
  repeated string room_numbers = 6;
  // По Лейблам помещений, привязанных ТУ
  repeated string room_labels = 7;
  // По ID привязанных точек учета
  repeated string metric_point_ids = 8;
  // По посреднику получения показаний
  repeated Indicator.VendorType indicator_vendor_types = 9;
}

// Запрос получения количества индикаторов
message GetDeviceIndicatorCountRequest {
  // Фильтр по индикаторам
  IndicatorFilter filter = 1;
}
// Ответ на запрос получения количества индикаторов
message GetDeviceIndicatorCountResponse {
  // Ошибка запроса получения количества индикаторов
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка фильтрации
      IndicatorFilter.ValidationError device_filter_validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Всего индикаторов
    int32 data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос удаления индикатора
message DeleteDeviceIndicatorRequest {
  // Идентификатор
  int32 id = 1 [(google.api.field_behavior) = REQUIRED];
}
// Ответ на запрос удаления индикатора
message DeleteDeviceIndicatorResponse {}

// Запрос создания задачи с клиента на сервере
message PostDeviceFullDuplexRequest {
  // Результат обработки устройства на клиенте
  message DeviceAsyncStatus {
    // Команда принята
    message Success {
    }
    // Ошибки обработки устройства на клиенте
    message Error {
      // Неизвестная ошибка на стороне клиента
      message UnknownError {
        // Произвольный текст ошибки на стороне клиента.
        // Отправляется в случае если в спецификации нет подходящей ошибки.
        // После анализа таких ошибок в спецификацию добавляется специальный тип под эту ошибку
        string message = 1 [(google.api.field_behavior) = REQUIRED];
      }
      // Причины:
      //  - Устройство не найденно на данном IP адресе
      message IpError {}
      // Причины:
      //  - Устройство отсутствует на порту
      message PortError {}
      // Причины:
      //  - Неверный сетевой адрес
      message NetworkAddressError {}

      // Причина ошибки
      oneof reason {
        // Неизвестная ошибка
        UnknownError post_device_request_unknown = 1;
        // Неверный IP
        IpError post_device_request_ip = 2;
        // Неверный порт
        PortError post_device_request_port = 3;
        // Неверный сетевой адрес
        NetworkAddressError post_device_request_network_address = 4;
      }
    }
    // Идентификатор ПУ
    int32 device_id = 1 [(google.api.field_behavior) = REQUIRED];
    // Тип результата
    oneof type {
      // Успех
      Success data = 2;
      // Ошибка
      Error error = 3;
    }
  }

  // Идентификатор запроса
  string request_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Задача с клиента
  oneof task {
    // Результат обработки устройства на клиенте
    DeviceAsyncStatus post_device_full_duplex_device_async_status = 2;
  }
}

// Запрос сохранения ПУ
message PostDeviceRequest {
  // Прибор учета
  Device device = 1 [(google.api.field_behavior) = REQUIRED];
}

// Запрос замены прибора учета
message PostDeviceReplaceRequest {
  // Идентификатор заменяемого прибора учета
  int32 replace_device_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Создаваемый прибор учета
  Device device = 2 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на замену прибора учета
message PostDeviceReplaceResponse {
  // Ошибка замены ПУ
  message Error {
    // Не найден заменяемый ПУ
    message ReplaceDeviceNotFound {}
    // Не удалось создать индикаторы нового ПУ
    message CreateIndicatorsFail {}
    // Попытка замены ПУ, привязанного ко многим ТУ
    message MultiLinkedMetricPoint {}
    // Заменяющий ПУ не привязан к дому заменяемого ПУ
    message WrongBuilding {}
    // Заменяемый ПУ не привязан к ТУ
    message MetricPointNotFound {}
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      Device.ValidationError validation = 1;
      // Не найден заменяемый ПУ
      ReplaceDeviceNotFound replace_device_not_found = 2;
      // Не удалось создать индикаторы нового ПУ
      CreateIndicatorsFail create_indicators_fail = 3;
      // Попытка замены ПУ, привязанного ко многим ТУ
      MultiLinkedMetricPoint multi_linked_metric_point = 4;
      // Заменяющий ПУ не привязан к дому заменяемого ПУ
      WrongBuilding wrong_building = 5;
      // Заменяемый ПУ не привязан к ТУ
      MetricPointNotFound metric_point_not_found = 6;
    }
  }
  // Тип ответа
  oneof type {
    // Созданный на замену ПУ
    Device data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Событие изменения ПУ на сервера
message PostDeviceFullDuplexResponse {
  // Идентификатор запроса
  string request_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Событие
  oneof event {
    // Измененние ПУ на сервере
    PostDeviceResponse post_device = 2;
  }
}

// Ответ на изменение ПУ на сервере
message PostDeviceResponse {
  // Ошибка запроса сохранения ПУ
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка валидации
      Device.ValidationError validation = 1;
    }
  }
  // Тип ответа
  oneof type {
    // ПУ
    Device data = 1;
    // Ошибка
    Error error = 2;
  }
}


// Индикатор
message Indicator {
  // Посредники получения показаний
  enum VendorType {
    // Значение не указано
    VENDOR_TYPE_UNKNOWN = 0;
    // Энвайро
    ENVIRO = 1;
    // Лартех
    LARTECH = 2;
    // РТК
    RTK = 3;
  }
  // Ошибки валидации.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Путь к полю в формате наименования protobuf
    string path = 1 [(google.api.field_behavior) = REQUIRED];
    // Валидационное сообщение
    string message = 2 [(google.api.field_behavior) = REQUIRED];
  }
  // Идентификатор
  int32 id = 1;
  // Идентификатор прибора учета(ПУ)
  int32 device_id = 2 [(google.api.field_behavior) = REQUIRED];
  // Название
  string title = 3 [(google.api.field_behavior) = REQUIRED];
  // Справочник типов единиц измерений
  enum UnitType {
    // Значение не указано
    UNIT_TYPE_UNKNOWN = 0;
    // Процент
    PERCENT = 1;
    // Градус по Цельсию
    C = 2;
    // Ватт
    WT = 3;
    // Гигакалория
    GKAL = 4;
    // Количество
    VALUE = 5;
    // Киловaтт-час
    KWH = 6;
    // Килограмм на квадратный сантиметр
    KG_CM2 = 7;
    // Килограмм-сила на квадратный сантиметр
    KGF_CM2 = 8;
    // Кубический метр
    M3 = 9;
    // Кубический метр в час
    M3_H = 10;
    // Мегапаскаль
    MPA = 11;
    // Миллисекунда
    MS = 12;
    // Флаг состояния
    BOOLEAN = 13;
    // Тонна
    T = 14;
    // Тонна в час
    T_H = 15;
    // Час
    H = 16;
    // Безразмерная величина
    NON_MEASURABLE = 17;
    // Импульс
    IMP = 18;
    // Джоуль
    J = 19;
    // Килоджоуль
    KJ = 20;
    // Гигаджоуль
    GJ = 21;
    // Ватт-час
    WTH = 22;
    // Киловатт
    KWT = 23;
    // Минута
    MIN = 24;
    // Секунда
    S = 25;
  }
  // Тип единицы измерения, в которой интерпретировано, получаемое измерение
  UnitType unit_type = 4 [(google.api.field_behavior) = REQUIRED];
  // Справочник типов измерений
  enum SignType {
    // Значение не указано
    SIGN_TYPE_UNKNOWN = 0;
    // Абсолютный показатель
    ABSOLUTE_DS = 1;
    // Абсолютный расход ресурса
    ABSOLUTE_RC = 2;
    // Интервальный показатель состояния
    INTERVAL_DS = 3;
    // Интервальный расход ресурса
    INTERVAL_RC = 4;
    // Текущее состояние
    CURRENT_DS = 5;
    // Текущее состояние ресурса
    CURRENT_RS = 6;
    // Объём
    VOLUME = 7;
    // Параметр конфигурации
    PARAMETER = 8;
    // Флаг состояния
    FLAG = 9;
  }
  // Тип измерения
  SignType sign_type = 5 [(google.api.field_behavior) = REQUIRED];
  // Дата создания
  google.protobuf.Timestamp created_at = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Дата последнего изменения.
  // Заполняется и обновляется сервером.
  // Заполняется при создании и изменении.
  // Является версией объекта
  google.protobuf.Timestamp changed_at = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Флаг видимости индикатора для клиента
  bool is_individual = 8;
  // Код для совместимости с поставщиком метрик
  google.protobuf.StringValue compatibility_code = 9;
  // Справочник типа архивности показаний.
  // Используется для указания за какой период произошло измерение.
  // По умолчанию CURRENT
  enum ArchiveType {
    // Значение не указано
    ARCHIVE_TYPE_UNKNOWN = 0;
    // Текущие показания
    CURRENT = 1;
    // За 30 мин
    HALFHOUR = 2;
    // За час
    HOUR = 3;
    // За сутки
    DAY = 4;
    // За месяц
    MONTH = 5;
    // За год
    YEAR = 6;
  }
  // Тип архивности показаний
  ArchiveType archive_type = 10;
  // Тип единицы измерения для отображения измерения.
  // При UNIT_TYPE_UNKNOWN отображаемые единицы совпадают с единицами источников значений, преобразования единиц не происходит.
  // Применяется после коэффициента
  UnitType presentation_unit_type = 11;
  // Коэффициент, на который умножается отображаемое значение.
  // Применяется перед преобразованием единиц измерений к presentation_unit_type и после применения поправки
  google.protobuf.FloatValue coefficient = 12;
  // Величина поправки к отображаемому значению.
  // Применяется перед применением коэффициента
  google.protobuf.FloatValue shift = 13;
  // Количество возвращаемых десятичных знаков при округлении итогового значения.
  // При пустом параметре округления не происходит.
  // Применяется после преобразования единиц измерения
  google.protobuf.Int32Value round_decimal_digits = 14;
  // Ожидаемая частота поступления показаний в днях
  int32 metric_expected_freq = 15;
  // Номер канала для многоканального ПУ
  google.protobuf.StringValue channel_number = 16;
  // Порядковый номер канала для многоканального ПУ
  google.protobuf.Int32Value channel_order = 17;
  // Посредник получения показаний
  VendorType vendor_type = 18;
}

// Прибор учёта
message Device {
  // Ошибки валидации.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Путь к полю в формате наименования protobuf
    string path = 1 [(google.api.field_behavior) = REQUIRED];
    // Валидационное сообщение
    string message = 2 [(google.api.field_behavior) = REQUIRED];
  }
  // Идентификатор
  int32 id = 1;
  // Индикаторы
  repeated Indicator indicators = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Справочник типов номинальных нагрузок вторичных обмоток.
  // У трансформаторов тока (В*А)
  enum SecondaryCurrentType {
    // Значение не указано
    SECONDARY_CURRENT_TYPE_UNKNOWN = 0;
    // 1 (А)
    TT1A = 1;
    // 2 (А)
    TT2A = 2;
    // 5 (А)
    TT5A = 3;
  }
  // Точка учета
  message MetricPoint {
    // Идентификатор
    string id = 1;
    // Справочние типов энергоресурсов
    enum MetricType {
      // Значение не указано
      METRIC_TYPE_UNKNOWN = 0;
      // Горячая вода
      HOT_WATER = 1;
      // Холодная вода
      COLD_WATER = 2;
      // Теплоэнергия
      HEAT = 3;
      // Газ
      GAS = 4;
      // Электроэнергия
      ELECTRICITY = 5;
    }
    // Тип энергоресурса
    MetricType metric_type = 2 [(google.api.field_behavior) = REQUIRED];
    // Номер помещения
    string room_number = 3 [(google.api.field_behavior) = REQUIRED];
    // Лейбл помещения
    string room_label = 4 [(google.api.field_behavior) = REQUIRED];
    // Зона
    google.protobuf.StringValue zone_label = 5;
    // Справочник типов статусов
    enum StatusType {
      // Значение не указано
      STATUS_TYPE_UNKNOWN = 0;
      // Активная
      ACTIVE = 1;
      // Не активная
      WRONG = 2 [deprecated = true, (google.api.value_visibility).restriction = "DEPRECATED"];
      // Архивная
      ARCHIVE = 3;
    }
    // Тип статуса
    StatusType status_type = 6 [(google.api.field_behavior) = REQUIRED];
    // Справочник типов учёта
    enum AccountingType {
      // Значение не указано
      ACCOUNTING_TYPE_UNKNOWN = 0;
      // Коммерческий учёт
      COMMERCIAL = 1;
      // Технический учёт
      TECHNICAL = 2;
    }
    // Тип учёта
    AccountingType accounting_type = 7 [(google.api.field_behavior) = REQUIRED];
    // Дата создания
    google.protobuf.Timestamp created_at = 8 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Справочник типов номиналов первичных токов.
    // У выпускаемых трансформаторов тока (А)
    enum PrimaryCurrentType {
      // Значение не указано
      PRIMARY_CURRENT_TYPE_UNKNOWN = 0;
      // 1 (А)
      TT1A = 1;
      // 5 (А)
      TT5A = 2;
      // 10 (А)
      TT10A = 3;
      // 15 (А)
      TT15A = 4;
      // 20 (А)
      TT20A = 5;
      // 30 (А)
      TT30A = 6;
      // 40 (А)
      TT40A = 7;
      // 50 (А)
      TT50A = 8;
      // 75 (А)
      TT75A = 9;
      // 80 (А)
      TT80A = 10;
      // 100 (А)
      TT100A = 11;
      // 150 (А)
      TT150A = 12;
      // 200 (А)
      TT200A = 13;
      // 300 (А)
      TT300A = 14;
      // 400 (А)
      TT400A = 15;
      // 500 (А)
      TT500A = 16;
      // 600 (А)
      TT600A = 17;
      // 750 (А)
      TT750A = 18;
      // 800 (А)
      TT800A = 19;
      // 1000 (А)
      TT1000A = 20;
      // 1200 (А)
      TT1200A = 21;
      // 1500 (А)
      TT1500A = 22;
      // 2000 (А)
      TT2000A = 23;
    }
    // Тип номинала первичного тока
    PrimaryCurrentType primary_current_type = 9;
    // Тип номинала вторичной обмотки
    SecondaryCurrentType secondary_current_type = 10;
    // Идентификатор объекта строительства
    int32 building_id = 11 [(google.api.field_behavior) = REQUIRED];
    // Дата изменения
    google.protobuf.Timestamp changed_at = 12 [(google.api.field_behavior) = OUTPUT_ONLY];
    // Уровень
    int32 building_level = 13;
    // Секция
    int32 building_section = 14;

  }
  // Точка учета
  MetricPoint metric_point = 3 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Дата создания
  google.protobuf.Timestamp created_at = 4 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Дата последнего изменения.
  // Заполняется и обновляется сервером.
  // Заполняется при создании и изменении.
  // Является версией объекта
  google.protobuf.Timestamp changed_at = 5 [(google.api.field_behavior) = OUTPUT_ONLY];
  // Справочник типов приборов учёта(ПУ)
  enum Type {
    // Значение не указано
    TYPE_UNKNOWN = 0;
    // Коммуникационный модуль
    HUB = 1;
    // Счетчик импульсов - регистратор
    PULSE_COUNTER_RECORDER = 2;
    // Счетчик импульсов - регистратор LoRaWAN
    PULSE_COUNTER_RECORDER_LR = 3;
    // Прибор учета расхода коммунальных услуг
    METERING_DEVICE = 4;
    // Конвертер интерфейсов
    INTERFACE_CONVERTER = 5;
    // M-BUS концентратор
    M_BUS_HUB = 6;
    // Модуль связи LoRaWAN
    COMMUNICATION_MODULE_LR = 7;
    // Базовая станция LoRaWAN
    BASE_LR = 8;
  }
  // Тип прибора учёта(ПУ)
  Type type = 6 [(google.api.field_behavior) = REQUIRED];
  // Серийный номер
  string serial_number = 7 [(google.api.field_behavior) = REQUIRED];
  // Производитель и модель счетчика
  string model = 8 [(google.api.field_behavior) = REQUIRED];
  // Год выпуска счётчика
  int32  year = 9 [(google.api.field_behavior) = REQUIRED, deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Идентификатор строения ФИАС
  string fias_id = 10 [(google.api.field_behavior) = REQUIRED, deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Идентификатор владельца.
  // Заполняется сервером
  string resource_owner_id = 11 [(google.api.field_behavior) = OUTPUT_ONLY, deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Справочник типов статусов
  enum StatusType {
    // Значение не указано
    STATUS_TYPE_UNKNOWN = 0;
    // Получен клиентом, еще не сконфигурирован
    RECEIVED = 1;
    // Сконфигурирован клиентом, активен
    ACTIVE = 2;
    // Обработан клиентом, возникла ошибка
    WRONG = 3;
    // Переведен в архивный статус
    ARCHIVE = 4;
    // Удален
    DELETE = 5;
    // Отсоединен
    UNLINK = 6;
  }
  // Тип статуса
  StatusType status_type = 12;
  // Дата установки
  google.protobuf.Timestamp installed_at = 13;
  // Дата удаления
  google.protobuf.Timestamp removed_at = 14;
  // Дата предыдущей поверки счетчика
  google.protobuf.Timestamp check_at = 15;
  // Дата следующей поверки счетчика
  google.protobuf.Timestamp next_check_at = 16;
  // Внешний дентификатор прибора учёта(ПУ)
  google.protobuf.StringValue external_id = 17;
  // Справочник типов тарифных планов
  enum PlanType {
    // Значение не указано
    PLAN_TYPE_UNKNOWN = 0;
    // Однотарифный
    SINGLE = 1;
    // Двухтарифный
    DOUBLE = 2;
    // Трёхтарифный
    TRIPLE = 3;
  }
  // Тип тарифного плана
  PlanType plan_type = 18;
  // Идентификатор хаба
  google.protobuf.Int32Value parent_id = 19;
  // Справочник типов трубопроводов
  enum PipeType {
    // Значение не указано
    PIPE_TYPE_UNKNOWN = 0;
    // Подающий
    INFEED = 1;
    // Циркуляционный
    CIRCULATING = 2;
  }
  // Тип трубопровода
  PipeType pipe_type = 20;
  // Идентификатор модуля LoraWan
  google.protobuf.StringValue dev_eui = 21;
  // MAC-адрес
  google.protobuf.StringValue mac = 22;
  // Номер порта
  google.protobuf.Int32Value port = 23;
  // Сетевой адрес
  google.protobuf.StringValue network_address = 24;
  // Канал связи.
  // Для станции LoraWan
  google.protobuf.StringValue comm_channel = 25;
  // MSISDN SIM-карты.
  // Номер телефона
  google.protobuf.StringValue sim_number = 26;
  // Серийный номер SIM-карты
  google.protobuf.StringValue sim_serial = 27;
  // IP адрес SIM-карты
  google.protobuf.StringValue ip_address_sim = 28;
  // Размещение
  google.protobuf.StringValue placement = 29;
  // Место установки
  google.protobuf.StringValue installation_place = 30;
  // Kлюч приложения.
  // Используется в процессе присоединения к сети для получения сессионных ключей NwkSKey и AppSKey для LoRaWAN [128 бит]
  google.protobuf.StringValue appkey = 31 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Идентификатор приложения.
  // Для LoRaWAN [64 бита]
  google.protobuf.StringValue appeui = 32 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Тип протокола
  google.protobuf.StringValue protocol_type_label = 33;
  // Номер канала для многоканального ПУ
  google.protobuf.Int32Value channel_number = 34 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // Тип проводного интерфейса
  google.protobuf.StringValue wire_interface = 35;
  // Идентификатор объекта строительства
  int32 building_id = 36;
  // Год выпуска счётчика
  google.protobuf.Int32Value manufacture_year = 37;
  // Посредник получения показаний
  Indicator.VendorType indicator_vendor_type = 38;
}

// Запрос получения списка
message GetDeviceListRequest {
  // Фильтр
  DeviceFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Пагинация
    DevicePaging paging = 2;
  }
}

// Пагинация устройств
message DevicePaging {
  // Ошибка валидации постраничной пагинации по ПУ.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Причины:
    // - Значение количества < 0 или > 100
    message LimitInvalid {}
    // Причины:
    // - Значение сдвига < 0
    message OffsetInvalid {}

    // Причина ошибки
    oneof reason {
      // Количество передано некорректно
      LimitInvalid limit = 1;
      // Сдвиг передан некорректно
      OffsetInvalid offset = 2;
    }
  }
  // Справочник типов значений сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По идентификатору
    ID = 1;
  }
  // Тип значения сортировки.
  // По умолчанию: ID
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Ответ на запрос получения списка приборов учета
message GetDeviceListResponse {
  // Ошибка запроса получения списка приборов учета
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка фильтрации
      DeviceFilter.ValidationError device_filter_validation = 1;
      // Ошибка пагинации  по страницам
      DevicePaging.ValidationError device_paging_validation = 2;
    }
  }
  // Тип результата
  oneof type {
    // Прибор учета
    Device data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Фильтр для запроса приборов учета.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message DeviceFilter {
  // Ошибки валидации.
  // Эти проверки выполняются до обращения в базу данных
  message ValidationError {
    // Путь к полю в формате наименования protobuf
    string path = 1 [(google.api.field_behavior) = REQUIRED];
    // Валидационное сообщение
    string message = 2 [(google.api.field_behavior) = REQUIRED];
  }
  // По ФИАС
  repeated string fias_ids = 1;
  // По типам приборов учета
  repeated Device.Type types = 2;
  // По типам статусов
  repeated Device.StatusType status_types = 3;
  // По модели счетчика
  repeated string models = 4;
  // По типам метрик
  repeated Device.MetricPoint.MetricType metric_point_metric_types = 5;
  // По номерам помещений точек учета, привязанных через индикаторы
  repeated string room_numbers = 6;
  // По лейблам помещений точек учета, привязанных через индикаторы
  repeated string room_labels = 7;
  // По идентификаторам хабов
  repeated int32 parent_ids = 8;
  // По идентификаторам приборов учета.
  // Устарело, использовать метод GetDevice
  repeated int32 ids = 9 [deprecated = true, (google.api.field_visibility).restriction = "DEPRECATED"];
  // По идентификатору объекта строительства
  repeated int32 building_ids = 10;
  // По серийным номерам
  repeated string serial_numbers = 11;
  // По ID точек учета, привязанных через индикаторы
  repeated string metric_point_ids = 12;
  // Смешанный поиск по полям serial_number, dev_eui, MAC-адрес, model, external_id
  repeated string serial_ids = 13;
  // По ОРПОНам
  repeated int64 orpons = 14;
  // По посреднику получения показаний
  repeated Indicator.VendorType indicator_vendor_types = 15;
}

// Запрос получения количества устройств
message GetDeviceCountRequest {
  // Фильтр по устройствам
  DeviceFilter filter = 1;
}

// Ответ на запрос получения количества устройств
message GetDeviceCountResponse {
  // Ошибка запроса получения количества устройств
  message Error {
    // Причина ошибки
    oneof reason {
      // Ошибка фильтрации
      DeviceFilter.ValidationError device_filter_validation = 1;
    }
  }
  // Тип результата
  oneof type {
    // Всего устройств
    int32 data = 1;
    // Ошибка
    Error error = 2;
  }
}

// Запрос получения списка
message GetDeviceIndicatorMetricPointListRequest {
  // Фильтр связей индикаторов и ТУ
  DeviceIndicatorMetricPointFilter filter = 1;
  // Вариант разбиения на страницы
  oneof pagination {
    // Пагинация
    DeviceIndicatorMetricPointPaging paging = 2;
  }
}

// Фильтр для запроса индикаторов и ТУ.
// При передаче массива в параметр фильтра элементы массива работают в выборке через ИЛИ.
// При передаче нескольких разных параметров фильтра они работают в выборке через И
message DeviceIndicatorMetricPointFilter {
  // По Идентификатору индикатора
  repeated int32 indicator_id = 1;
  // По Идентификатору ТУ
  repeated string metric_point_id = 2;
}

// Пагинация связей индикаторов и ТУ
message DeviceIndicatorMetricPointPaging {
  // Справочник типов сортировки
  enum OrderByType {
    // Значение не указано
    ORDER_BY_TYPE_UNKNOWN = 0;
    // По Идентификатору индикатора
    INDICATOR_ID = 1;
    // По По Идентификатору ТУ
    METRIC_POINT_ID = 2;
  }
  // Тип значения сортировки.
  // По умолчанию: ID
  OrderByType order_by_type = 1;
  // Справочник типов направлений сортировки
  enum DirectionType {
    // Значение не указано
    DIRECTION_TYPE_UNKNOWN = 0;
    // От большего к меньшему
    DESC = 1;
    // От меньшего к большему
    ASC = 2;
  }
  // Тип направления сортировки.
  // По умолчанию: DESC
  DirectionType direction_type = 2;
  // Количество записей на страницу.
  // Минимальное значение: 1.
  // Максимальное значение: 100.
  // По умолчанию: 20.
  // Если значение 0 (не передано), то выставляем значение по умолчанию
  int32 limit = 3;
  // Сдвиг.
  // По умолчанию: 0
  int32 offset = 4;
}

// Ответ на запрос получения списка связей индикаторов и ТУ
message GetDeviceIndicatorMetricPointListResponse {
  // Тип результата
  oneof type {
    // Связь индикатора и ТУ
    DeviceIndicatorMetricPoint data = 1;
  }
}

// Связка индикатора и ТУ
message DeviceIndicatorMetricPoint {
  // Идентификатор индикатора.
  // # Диапазон: 0..2147483647
  int32 indicator_id = 1 [(google.api.field_behavior) = REQUIRED];
  // Идентификатору ТУ.
  // # Тип: Guid
  string metric_point_id = 2 [(google.api.field_behavior) = REQUIRED];
}

// Запрос получения количества связей индикаторов и ТУ
message GetDeviceIndicatorMetricPointCountRequest {
  // Фильтр связей индикаторов и ТУ
  DeviceIndicatorMetricPointFilter filter = 1;
}

// Ответ на запрос получения количества связей индикаторов и ТУ
message GetDeviceIndicatorMetricPointCountResponse {
  // Тип результата
  oneof type {
    // Всего связей индикаторов и ТУ
    int32 data = 1;
  }
}

// Запрос сохранения связей индикаторов и ТУ
message PutDeviceIndicatorMetricPointAttachRequest {
  // Связь индикатора и ТУ
  DeviceIndicatorMetricPoint device_indicator_metric_point = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос сохранения связи индикатора и ТУ
message PutDeviceIndicatorMetricPointAttachResponse {}

// Запрос удаления связей индикаторов и ТУ
message PutDeviceIndicatorMetricPointDetachRequest {
  // Связь индикатора и ТУ
  DeviceIndicatorMetricPoint device_indicator_metric_point = 1 [(google.api.field_behavior) = REQUIRED];
}

// Ответ на запрос удаления связи индикатора и ТУ
message PutDeviceIndicatorMetricPointDetachResponse {}
