#============================================================================ # This library is free software; you can redistribute it and/or # modify it under the terms of version 2.1 of the GNU Lesser General Public # License as published by the Free Software Foundation. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #============================================================================ # Copyright (C) 2004, 2005 Mike Wray #============================================================================ """Encoding for arguments to HTTP calls. Uses the url-encoding with MIME type 'application/x-www-form-urlencoded' if the data does not include files. Otherwise it uses the encoding with MIME type 'multipart/form-data'. See the HTML4 spec for details. """ import sys import types from StringIO import StringIO import urllib import random import md5 # Extract from HTML4 spec. ## The following example illustrates "multipart/form-data" ## encoding. Suppose we have the following form: ##
##

## What is your name?
## What files are you sending?
## ##

## If the user enters "Larry" in the text input, and selects the text ## file "file1.txt", the user agent might send back the following data: ## Content-Type: multipart/form-data; boundary=AaB03x ## --AaB03x ## Content-Disposition: form-data; name="submit-name" ## Larry ## --AaB03x ## Content-Disposition: form-data; name="files"; filename="file1.txt" ## Content-Type: text/plain ## ... contents of file1.txt ... ## --AaB03x-- ## If the user selected a second (image) file "file2.gif", the user agent ## might construct the parts as follows: ## Content-Type: multipart/form-data; boundary=AaB03x ## --AaB03x ## Content-Disposition: form-data; name="submit-name" ## Larry ## --AaB03x ## Content-Disposition: form-data; name="files" ## Content-Type: multipart/mixed; boundary=BbC04y ## --BbC04y ## Content-Disposition: file; filename="file1.txt" ## Content-Type: text/plain ## ... contents of file1.txt ... ## --BbC04y ## Content-Disposition: file; filename="file2.gif" ## Content-Type: image/gif ## Content-Transfer-Encoding: binary ## ...contents of file2.gif... ## --BbC04y-- ## --AaB03x-- __all__ = ['encode_data', 'encode_multipart', 'encode_form', 'mime_boundary' ] def data_values(d): if isinstance(d, types.DictType): return d.items() else: return d def encode_data(d): """Encode some data for HTTP transport. The encoding used is stored in 'Content-Type' in the headers. d data - sequence of tuples or dictionary returns a 2-tuple of the headers and the encoded data """ val = ({}, None) if d is None: return val multipart = 0 for (_, v) in data_values(d): if encode_isfile(v): multipart = 1 break if multipart: val = encode_multipart(d) else: val = encode_form(d) return val def encode_isfile(v): if isinstance(v, types.FileType): return 1 if hasattr(v, 'readlines'): return 1 return 0 def encode_multipart(d): boundary = mime_boundary() hdr = { 'Content-Type': 'multipart/form-data; boundary=' + boundary } out = StringIO() for (k,v) in data_values(d): out.write('--') out.write(boundary) out.write('\r\n') if encode_isfile(v): out.write('Content-Disposition: form-data; name="') out.write(k) if hasattr(v, 'name'): out.write('"; filename="') out.write(v.name) out.write('"\r\n') out.write('Content-Type: application/octet-stream\r\n') out.write('\r\n') for l in v.readlines(): out.write(l) else: out.write('Content-Disposition: form-data; name="') out.write(k) out.write('"\r\n') out.write('\r\n') out.write(str(v)) out.write('\r\n') out.write('--') out.write(boundary) out.write('--') out.write('\r\n') return (hdr, out.getvalue()) def mime_boundary(): random.seed() m = md5.new() for _ in range(0, 10): c = chr(random.randint(1, 255)) m.update(c) b = m.hexdigest() return b[0:16] def encode_form(d):
# QMK API

This page describes using the QMK API. If you are an application developer you can use this API to compile firmware for any [QMK](https://qmk.fm) Keyboard.

## Overview

This service is an asynchronous API for compiling custom keymaps. You POST some JSON to the API, periodically check the status, and when your firmware has finished compiling you can download the resulting firmware and (if desired) source code for that firmware.

#### Example JSON Payload:

```json
{
  "keyboard": "clueboard/66/rev2",
  "keymap": "my_awesome_keymap",
  "layout": "LAYOUT_all",
  "layers": [
    ["KC_GRV","KC_1","KC_2","KC_3","KC_4","KC_5","KC_6","KC_7","KC_8","KC_9","KC_0","KC_MINS","KC_EQL","KC_GRV","KC_BSPC","KC_PGUP","KC_TAB","KC_Q","KC_W","KC_E","KC_R","KC_T","KC_Y","KC_U","KC_I","KC_O","KC_P","KC_LBRC","KC_RBRC","KC_BSLS","KC_PGDN","KC_CAPS","KC_A","KC_S","KC_D","KC_F","KC_G","KC_H","KC_J","KC_K","KC_L","KC_SCLN","KC_QUOT","KC_NUHS","KC_ENT","KC_LSFT","KC_NUBS","KC_Z","KC_X","KC_C","KC_V","KC_B","KC_N","KC_M","KC_COMM","KC_DOT","KC_SLSH","KC_RO","KC_RSFT","KC_UP","KC_LCTL","KC_LGUI","KC_LALT","KC_MHEN","KC_SPC","KC_SPC","KC_HENK","KC_RALT","KC_RCTL","MO(1)","KC_LEFT","KC_DOWN","KC_RIGHT"],
    ["KC_ESC","KC_F1","KC_F2","KC_F3","KC_F4","KC_F5","KC_F6","KC_F7","KC_F8","KC_F9","KC_F10","KC_F11","KC_F12","KC_TRNS","KC_DEL","BL_STEP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","_______","KC_TRNS","KC_PSCR","KC_SLCK","KC_PAUS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(2)","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_PGUP","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(1)","KC_LEFT","KC_PGDN","KC_RGHT"],
    ["KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","RESET","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(2)","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","KC_TRNS","MO(1)","KC_TRNS","KC_TRNS","KC_TRNS"]
  ]
}
```

As you can see the payload describes all aspects of a keyboard necessary to create and generate a firmware. Each layer is a single list of QMK keycodes the same length as the keyboard's `LAYOUT` macro. If a keyboard supports mulitple `LAYOUT` macros you can specify which macro to use.

## Submitting a Compile Job

To compile your keymap into a firmware simply POST your JSON to the `/v1/compile` endpoint. In the following example we've placed the JSON payload into a file named `json_data`.

```
$ curl -H "Content-Type: application/json" -X POST -d "$(< json_data)" http://api.qmk.fm/v1/compile
{
  "enqueued": true,
  "job_id": "ea1514b3-bdfc-4a7b-9b5c-08752684f7f6"
}
```

## Checking The Status

After submitting your keymap you can check the status using a simple HTTP GET call:

```
$ curl http://api.qmk.fm/v1/compile/ea1514b3-bdfc-4a7b-9b5c-08752684f7f6
{
  "created_at": "Sat, 19 Aug 2017 21:39:12 GMT",
  "enqueued_at": "Sat, 19 Aug 2017 21:39:12 GMT",
  "id": "f5f9b992-73b4-479b-8236-df1deb37c163",
  "status": "running",
  "result": null
}
```

This shows us that the job has made it through the queue and is currently running. There are 5 possible statuses:

* **failed**: Something about the compiling service has broken.
* **finished**: The compilation is complete and you should check `result` to see the results.
* **queued**: The keymap is waiting for a compilation server to become available.
* **running**: The compilation is in progress and should be complete soon.
* **unknown**: A serious error has occurred and you should [file a bug](https://github.com/qmk/qmk_compiler/issues).

## Examining Finished Results

Once your compile job has finished you'll check the `result` key. The value of this key is a hash containing several key bits of information:

* `firmware_binary_url`: A list of URLs for the the flashable firmware
* `firmware_keymap_url`: A list of URLs for the the `keymap.c`
* `firmware_source_url`: A list of URLs for the full firmware source code
* `output`: The stdout and stderr for this compile job. Errors will be found here.