openapi: 3.0.3 info: title: miniPLC REST API v1 version: "1.0.0" description: > API REST v1 do miniPLC. Quando a autenticação da API estiver habilitada, use Authorization: Bearer . Token READ permite GET. Token WRITE permite GET e POST. Esta versão documenta CORS/preflight OPTIONS e o endpoint de reboot. servers: - url: http://{host} description: miniPLC local variables: host: default: 192.168.17.51 description: IP ou hostname do miniPLC tags: - name: System description: Estado, informações e reboot do equipamento - name: IO description: Leitura e comando das variáveis de entrada, saída e virtuais - name: DateTime description: Leitura e ajuste de data/hora paths: /api/v1/health: get: summary: Estado geral do dispositivo description: Requer token READ ou WRITE. tags: [System] security: [{BearerAuth: []}] responses: "200": description: Estado geral content: application/json: schema: {$ref: "#/components/schemas/HealthResponse"} example: ok: true status: ok uptime_s: 12345 epoch: 1783193400 "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} options: summary: CORS preflight tags: [System] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/info: get: summary: Informações do dispositivo description: Requer token READ ou WRITE. tags: [System] security: [{BearerAuth: []}] responses: "200": description: Informações do miniPLC content: application/json: schema: {$ref: "#/components/schemas/InfoResponse"} example: ok: true board_id: "MINIPLC" serial_id: "00000001" version: "1.0.0" language: "pt-BR" media: wired mac: "AA:BB:CC:DD:EE:FF" ip: "192.168.17.51" dns1: "8.8.8.8" dns2: "8.8.4.4" gateway: "192.168.17.1" mask: "255.255.255.0" runtime: uptime_s: 12345 epoch: 1783193400 "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} options: summary: CORS preflight tags: [System] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/reboot: post: summary: Reinicia o dispositivo description: Requer token WRITE. O body é opcional. tags: [System] security: [{BearerAuth: []}] requestBody: required: false content: application/json: schema: type: object additionalProperties: true example: {} responses: "200": description: Reboot agendado content: application/json: schema: {$ref: "#/components/schemas/RebootResponse"} example: ok: true message: "Reboot agendado." delay_ms: 500 "400": {$ref: "#/components/responses/BadRequest"} "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ForbiddenOrDisabled"} "500": {$ref: "#/components/responses/InternalError"} options: summary: CORS preflight tags: [System] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/map: get: summary: Mapa de nomes/tags das variáveis description: Requer token READ ou WRITE. Retorna os nomes padrão DI, DO, VB e VL. tags: [IO] security: [{BearerAuth: []}] responses: "200": description: Mapa de variáveis content: application/json: schema: {$ref: "#/components/schemas/MapResponse"} example: ok: true di: [DI1, DI2, DI3] do: [DO1, DO2, DO3] vb: [VB1, VB2, VB3] vl: [VL1, VL2, VL3] "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} options: summary: CORS preflight tags: [IO] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/io: get: summary: Snapshot completo das variáveis de IO description: Requer token READ ou WRITE. tags: [IO] security: [{BearerAuth: []}] responses: "200": description: Snapshot de IO content: application/json: schema: {$ref: "#/components/schemas/IOSnapshotResponse"} example: ok: true di: [0, 1, 0, 0] do: [1, 0, 0, 0] vb: [true, false, false, true] vl: [123, 0, -10, 456] "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} options: summary: CORS preflight tags: [IO] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/io/{kind}/{idx}: get: summary: Lê uma variável específica description: > Requer token READ ou WRITE. kind pode ser di, do, vb ou vl. idx usa base 1. tags: [IO] security: [{BearerAuth: []}] parameters: - {$ref: "#/components/parameters/IoKind"} - {$ref: "#/components/parameters/IoIndex"} responses: "200": description: Valor da variável content: application/json: schema: {$ref: "#/components/schemas/IOValueResponse"} examples: digital_output: value: {ok: true, kind: do, idx: 1, value: 1} virtual_bool: value: {ok: true, kind: vb, idx: 1, value: true} virtual_long: value: {ok: true, kind: vl, idx: 1, value: 12345} "400": {$ref: "#/components/responses/BadRequest"} "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} "404": {$ref: "#/components/responses/NotFound"} post: summary: Ajusta uma variável específica description: > Requer token WRITE. Escrita permitida apenas para kind do, vb e vl. Para do, o campo opcional pulse_ms comanda pulso: aplica value imediatamente e, ao final do tempo, retorna ao valor oposto. pulse_ms é limitado a 0..60000 ms. tags: [IO] security: [{BearerAuth: []}] parameters: - {$ref: "#/components/parameters/IoKind"} - {$ref: "#/components/parameters/IoIndex"} requestBody: required: true content: application/json: schema: {$ref: "#/components/schemas/IOSetRequest"} examples: set_do: value: {value: 1} pulse_do: value: {value: 1, pulse_ms: 500} set_vb: value: {value: true} set_vl: value: {value: 12345} responses: "200": description: Variável ajustada content: application/json: schema: {$ref: "#/components/schemas/IOSetResponse"} examples: set_do: value: {ok: true, kind: do, idx: 1, value: 1} pulse_do: value: {ok: true, kind: do, idx: 1, value: 1, pulse_ms: 500, during: 1, final: 0} set_vb: value: {ok: true, kind: vb, idx: 1, value: true} set_vl: value: {ok: true, kind: vl, idx: 1, value: 12345} "400": {$ref: "#/components/responses/BadRequest"} "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ForbiddenOrDisabled"} "404": {$ref: "#/components/responses/NotFound"} "405": {$ref: "#/components/responses/MethodNotAllowed"} options: summary: CORS preflight tags: [IO] parameters: - {$ref: "#/components/parameters/IoKind"} - {$ref: "#/components/parameters/IoIndex"} responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/get_datetime: get: summary: Lê a data/hora atual description: Requer token READ ou WRITE. tags: [DateTime] security: [{BearerAuth: []}] responses: "200": description: Data/hora atual content: application/json: schema: {$ref: "#/components/schemas/DateTimeResponse"} example: ok: true datetime: "04/07/2026 15:30:00" epoch: 1783193400 "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ApiDisabled"} options: summary: CORS preflight tags: [DateTime] responses: "204": {$ref: "#/components/responses/CorsNoContent"} /api/v1/set_datetime: post: summary: Ajusta a data/hora description: Requer token WRITE. tags: [DateTime] security: [{BearerAuth: []}] requestBody: required: true content: application/json: schema: {$ref: "#/components/schemas/DateTimeSetRequest"} example: year: 2026 mon: 7 day: 4 hour: 15 min: 30 sec: 0 responses: "200": description: Data/hora ajustada content: application/json: schema: {$ref: "#/components/schemas/DateTimeResponse"} example: ok: true datetime: "04/07/2026 15:30:00" epoch: 1783193400 "400": {$ref: "#/components/responses/BadRequest"} "401": {$ref: "#/components/responses/Unauthorized"} "403": {$ref: "#/components/responses/ForbiddenOrDisabled"} "500": {$ref: "#/components/responses/InternalError"} options: summary: CORS preflight tags: [DateTime] responses: "204": {$ref: "#/components/responses/CorsNoContent"} components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: Token parameters: IoKind: name: kind in: path required: true description: Tipo da variável. Para POST, use apenas do, vb ou vl. schema: type: string enum: [di, do, vb, vl] example: do IoIndex: name: idx in: path required: true description: Índice da variável na API, usando base 1. schema: type: integer minimum: 1 maximum: 32 example: 1 responses: CorsNoContent: description: No Content headers: Access-Control-Allow-Origin: schema: {type: string} example: "*" Access-Control-Allow-Methods: schema: {type: string} example: "GET,POST,OPTIONS" Access-Control-Allow-Headers: schema: {type: string} example: "Content-Type,Authorization" BadRequest: description: Requisição inválida content: application/json: schema: {$ref: "#/components/schemas/ErrorResponse"} examples: bad_request: value: {ok: false, code: bad_request, message: "Requisição inválida."} bad_json: value: {ok: false, code: bad_json, message: "JSON inválido."} Unauthorized: description: Token ausente ou inválido headers: WWW-Authenticate: schema: {type: string} example: Bearer content: application/json: schema: {$ref: "#/components/schemas/AuthErrorResponse"} examples: missing: {value: {ok: false, error: missing_bearer_token}} invalid: {value: {ok: false, error: invalid_token}} ApiDisabled: description: API desabilitada na configuração do dispositivo content: application/json: schema: {$ref: "#/components/schemas/AuthErrorResponse"} example: {ok: false, error: api_disabled} ForbiddenOrDisabled: description: Token sem permissão para escrita ou API desabilitada content: application/json: schema: {$ref: "#/components/schemas/AuthErrorResponse"} examples: write_token_required: {value: {ok: false, error: write_token_required}} api_disabled: {value: {ok: false, error: api_disabled}} NotFound: description: Recurso não encontrado ou índice fora do range content: application/json: schema: {$ref: "#/components/schemas/ErrorResponse"} example: {ok: false, code: not_found, message: "idx fora do range."} MethodNotAllowed: description: Método não permitido para este recurso content: application/json: schema: {$ref: "#/components/schemas/ErrorResponse"} example: {ok: false, code: method_not_allowed, message: "Escrita permitida apenas em do/vb/vl."} InternalError: description: Falha interna content: application/json: schema: {$ref: "#/components/schemas/ErrorResponse"} example: {ok: false, code: internal_error, message: "Falha interna."} schemas: ErrorResponse: type: object properties: ok: {type: boolean, example: false} code: {type: string, example: bad_request} message: {type: string, example: "Requisição inválida."} AuthErrorResponse: type: object properties: ok: {type: boolean, example: false} error: {type: string, example: invalid_token} HealthResponse: type: object properties: ok: {type: boolean, example: true} status: {type: string, example: ok} uptime_s: {type: integer, example: 12345} epoch: {type: integer, example: 1783193400} RuntimeInfo: type: object properties: uptime_s: {type: integer, example: 12345} epoch: {type: integer, example: 1783193400} InfoResponse: type: object properties: ok: {type: boolean, example: true} board_id: {type: string, example: "MINIPLC"} serial_id: {type: string, example: "00000001"} version: {type: string, example: "1.0.0"} language: {type: string, example: "pt-BR"} media: {type: string, enum: [wired, wireless], example: wired} mac: {type: string, example: "AA:BB:CC:DD:EE:FF"} ip: {type: string, example: "192.168.17.51"} dns1: {type: string, example: "8.8.8.8"} dns2: {type: string, example: "8.8.4.4"} gateway: {type: string, example: "192.168.17.1"} mask: {type: string, example: "255.255.255.0"} runtime: {$ref: "#/components/schemas/RuntimeInfo"} RebootResponse: type: object properties: ok: {type: boolean, example: true} message: {type: string, example: "Reboot agendado."} delay_ms: {type: integer, example: 500} MapResponse: type: object properties: ok: {type: boolean, example: true} di: type: array items: {type: string} example: [DI1, DI2, DI3] do: type: array items: {type: string} example: [DO1, DO2, DO3] vb: type: array items: {type: string} example: [VB1, VB2, VB3] vl: type: array items: {type: string} example: [VL1, VL2, VL3] DigitalArray: type: array items: type: integer enum: [0, 1] BoolArray: type: array items: type: boolean LongArray: type: array items: type: integer format: int32 IOSnapshotResponse: type: object properties: ok: {type: boolean, example: true} di: {$ref: "#/components/schemas/DigitalArray"} do: {$ref: "#/components/schemas/DigitalArray"} vb: {$ref: "#/components/schemas/BoolArray"} vl: {$ref: "#/components/schemas/LongArray"} IOValue: oneOf: - type: integer enum: [0, 1] - type: boolean - type: integer format: int32 IOValueResponse: type: object properties: ok: {type: boolean, example: true} kind: {type: string, enum: [di, do, vb, vl], example: do} idx: {type: integer, minimum: 1, maximum: 32, example: 1} value: {$ref: "#/components/schemas/IOValue"} IOSetRequest: type: object required: [value] properties: value: oneOf: - type: integer format: int32 - type: boolean example: 1 pulse_ms: type: integer minimum: 0 maximum: 60000 description: Usado apenas em DO. Se maior que 0, aplica pulso e retorna ao oposto. example: 500 IOSetResponse: allOf: - {$ref: "#/components/schemas/IOValueResponse"} - type: object properties: pulse_ms: {type: integer, example: 500} during: {type: integer, enum: [0, 1], example: 1} final: {type: integer, enum: [0, 1], example: 0} DateTimeSetRequest: type: object required: [year, mon, day, hour, min, sec] properties: year: {type: integer, minimum: 1970, maximum: 9999, example: 2026} mon: {type: integer, minimum: 1, maximum: 12, example: 7} day: {type: integer, minimum: 1, maximum: 31, example: 4} hour: {type: integer, minimum: 0, maximum: 23, example: 15} min: {type: integer, minimum: 0, maximum: 59, example: 30} sec: {type: integer, minimum: 0, maximum: 59, example: 0} DateTimeResponse: type: object properties: ok: {type: boolean, example: true} datetime: {type: string, example: "04/07/2026 15:30:00"} epoch: {type: integer, example: 1783193400}