├── .devcontainer └── devcontainer.json ├── .eleventy.js ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .node-version ├── netlify.toml ├── package-lock.json ├── package.json ├── public ├── _redirects ├── images │ ├── clockwise.png │ ├── esp-web-tools.svg │ ├── esphome.svg │ ├── home-assistant.svg │ ├── improv-favicon.png │ ├── improv-logo.svg │ ├── improv-states.svg │ ├── luciferin_logo.png │ ├── social.png │ ├── tasmota.svg │ └── wled.png └── style.css ├── script ├── build ├── develop ├── download_js_ble_sdk └── download_js_serial_sdk └── src ├── _includes └── base.html ├── ble.md ├── code.md ├── index.html └── serial.md /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Improv WiFi website", 3 | "image": "mcr.microsoft.com/vscode/devcontainers/typescript-node:14", 4 | "postCreateCommand": "npm install", 5 | "context": "..", 6 | "appPort": 5000, 7 | "extensions": ["esbenp.prettier-vscode"] 8 | } 9 | -------------------------------------------------------------------------------- /.eleventy.js: -------------------------------------------------------------------------------- 1 | module.exports = function (eleventyConfig) { 2 | return { 3 | dir: { 4 | input: "src", 5 | output: "dist", 6 | }, 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | - package-ecosystem: "npm" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: CI 5 | 6 | on: 7 | push: 8 | branches: [main] 9 | pull_request: 10 | branches: [main] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Use Node.js 19 | uses: actions/setup-node@v3 20 | with: 21 | node-version: 14 22 | - run: npm ci 23 | - run: npm test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .rpt2_cache 4 | .DS_Store 5 | manifest.json 6 | .vscode/settings.json 7 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [[headers]] 2 | for = "/sdk-js/*" 3 | [headers.values] 4 | Access-Control-Allow-Origin = "*" 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "true" 4 | }, 5 | "devDependencies": { 6 | "@11ty/eleventy": "^2.0.1", 7 | "serve": "^14.2.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | # These redirects are handled by Netlify 2 | 3 | /documentation /ble 4 | -------------------------------------------------------------------------------- /public/images/clockwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/improv-wifi/website/4794bd310f4a1470e64ff989062f5da6e61116ed/public/images/clockwise.png -------------------------------------------------------------------------------- /public/images/esp-web-tools.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/esphome.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/home-assistant.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logo-pretty 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /public/images/improv-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/improv-wifi/website/4794bd310f4a1470e64ff989062f5da6e61116ed/public/images/improv-favicon.png -------------------------------------------------------------------------------- /public/images/improv-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/images/improv-states.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /public/images/luciferin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/improv-wifi/website/4794bd310f4a1470e64ff989062f5da6e61116ed/public/images/luciferin_logo.png -------------------------------------------------------------------------------- /public/images/social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/improv-wifi/website/4794bd310f4a1470e64ff989062f5da6e61116ed/public/images/social.png -------------------------------------------------------------------------------- /public/images/tasmota.svg: -------------------------------------------------------------------------------- 1 | Element 1 2 | -------------------------------------------------------------------------------- /public/images/wled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/improv-wifi/website/4794bd310f4a1470e64ff989062f5da6e61116ed/public/images/wled.png -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, 3 | Ubuntu, sans-serif; 4 | padding: 0; 5 | margin: 0; 6 | line-height: 1.4; 7 | } 8 | 9 | a { 10 | color: #03a9f4; 11 | } 12 | .container { 13 | margin: 0 auto; 14 | padding: 16px 8px; 15 | max-width: 600px; 16 | } 17 | h3 { 18 | margin: 2rem 0 1rem; 19 | } 20 | .header { 21 | display: flex; 22 | justify-content: space-between; 23 | align-items: center; 24 | } 25 | .header img { 26 | height: 48px; 27 | margin-left: -7px; 28 | } 29 | .header ul { 30 | display: flex; 31 | justify-content: space-between; 32 | padding: 0; 33 | } 34 | .header ul li { 35 | list-style: none; 36 | } 37 | .header li a { 38 | display: inline-block; 39 | padding: 4px; 40 | margin: 0 4px; 41 | color: black; 42 | text-decoration: none; 43 | border-bottom: 2px solid transparent; 44 | } 45 | .header a.active { 46 | border-bottom-color: #03a9f4; 47 | } 48 | .content li { 49 | padding: 4px 0; 50 | } 51 | .content img { 52 | max-width: 100%; 53 | } 54 | .content pre { 55 | max-width: 100%; 56 | overflow-y: scroll; 57 | } 58 | improv-wifi-launch-button, 59 | improv-wifi-serial-launch-button { 60 | display: inline-block; 61 | } 62 | improv-wifi-launch-button[supported], 63 | improv-wifi-serial-launch-button[supported] { 64 | margin-right: 1em; 65 | } 66 | .projects { 67 | display: flex; 68 | text-align: center; 69 | flex-wrap: wrap; 70 | gap: 24px; 71 | justify-content: center; 72 | } 73 | .projects a { 74 | color: initial; 75 | text-decoration: none; 76 | } 77 | .project .logo > * { 78 | height: 50px; 79 | } 80 | .project .name { 81 | margin-top: 8px; 82 | } 83 | .center { 84 | text-align: center; 85 | } 86 | .videoWrapper { 87 | position: relative; 88 | padding-bottom: 56.25%; /* 16:9 */ 89 | height: 0; 90 | margin-bottom: 25px; 91 | background: #ccc; 92 | } 93 | 94 | .footer { 95 | margin-top: 24px; 96 | border-top: 1px solid #ccc; 97 | padding-top: 24px; 98 | text-align: center; 99 | } 100 | .footer .initiative { 101 | font-style: italic; 102 | margin-top: 16px; 103 | } 104 | .hidden { 105 | display: none; 106 | } 107 | table { 108 | width: 100%; 109 | border: 1px solid #e3e3e3; 110 | border-radius: 4px; 111 | } 112 | 113 | th { 114 | background-color: #e3e3e3; 115 | } 116 | 117 | th, 118 | td { 119 | padding: 4px; 120 | } 121 | -------------------------------------------------------------------------------- /script/build: -------------------------------------------------------------------------------- 1 | # Stop on errors 2 | set -e 3 | 4 | cd "$(dirname "$0")/.." 5 | 6 | rm -rf dist 7 | cp -r public dist 8 | script/download_js_ble_sdk 9 | script/download_js_serial_sdk 10 | 11 | NODE_ENV=production npm exec -- eleventy 12 | -------------------------------------------------------------------------------- /script/develop: -------------------------------------------------------------------------------- 1 | # Stop on errors 2 | set -e 3 | 4 | cd "$(dirname "$0")/.." 5 | 6 | rm -rf dist 7 | cp -r public dist 8 | script/download_js_ble_sdk 9 | script/download_js_serial_sdk 10 | 11 | # Quit all background tasks when script exits 12 | trap "kill 0" EXIT 13 | 14 | npm exec -- serve -p 5005 dist & 15 | npm exec -- eleventy --watch & 16 | wait 17 | -------------------------------------------------------------------------------- /script/download_js_ble_sdk: -------------------------------------------------------------------------------- 1 | # Stop on errors 2 | set -e 3 | 4 | cd "$(dirname "$0")/.." 5 | 6 | SDK_VER=latest 7 | 8 | DOWNLOAD_URL=$(npm view improv-wifi-sdk@$SDK_VER dist.tarball) 9 | 10 | rm -rf dist/sdk-ble-js 11 | mkdir -p dist/sdk-ble-js 12 | 13 | curl $DOWNLOAD_URL | tar zx -C dist/sdk-ble-js --strip-components 3 package/dist/web 14 | -------------------------------------------------------------------------------- /script/download_js_serial_sdk: -------------------------------------------------------------------------------- 1 | # Stop on errors 2 | set -e 3 | 4 | cd "$(dirname "$0")/.." 5 | 6 | SDK_VER=latest 7 | 8 | DOWNLOAD_URL=$(npm view improv-wifi-serial-sdk@$SDK_VER dist.tarball) 9 | 10 | rm -rf dist/sdk-serial-js 11 | mkdir -p dist/sdk-serial-js 12 | 13 | curl $DOWNLOAD_URL | tar zx -C dist/sdk-serial-js --strip-components 3 package/dist/web 14 | -------------------------------------------------------------------------------- /src/_includes/base.html: -------------------------------------------------------------------------------- 1 | --- 2 | menu: 3 | - - / 4 | - Home 5 | - - /ble/ 6 | - BLE 7 | - - /serial/ 8 | - Serial 9 | - - /code/ 10 | - Code 11 | --- 12 | 13 | {% comment %} 14 | 15 | {% endcomment %} 16 | {% capture full_title -%} 17 | {%- if title -%} 18 | {{ title }} – Improv Wi-Fi 19 | {%- else -%} 20 | Improv Wi-Fi: Open standard for setting up Wi-Fi via Bluetooth LE and Serial 21 | {%- endif -%} 22 | {%- endcapture %} 23 | {% comment %} 24 | 25 | {% endcomment %} 26 | 27 | 28 | 29 | 30 | 31 | {{ full_title }} 32 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 54 | 55 | 56 | 57 | 58 |
59 |
60 | Improv logo 61 | 72 |
73 | 74 |
{{ content }}
75 | 76 | 91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /src/ble.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: Improv via BLE 4 | description: All the implementation details necessary to make your own client and service implementation. 5 | --- 6 | 7 | This is the description of the Improv Wi-Fi protocol using Bluetooth Low Energy. 8 | 9 | The protocol has two actors: the Improv service running on the gadget and the Improv client. 10 | 11 | The Improv service will broadcast its presence via Bluetooth LE and receives Wi-Fi credentials from the client. 12 | 13 | The Improv client detects the service via Bluetooth LE and will offer the user to send Wi-Fi credentials. 14 | 15 | ## Improv Service 16 | 17 | The Improv service runs on a gadget that needs to connect to the internet but has no credentials or is unable to establish a connection. 18 | 19 | The Improv service can optionally require physical authorization to allow pairing, like pressing a button. It is up to the gadget to decide if and what interaction to pick. A gadget that does not require authorization should start in the "authorized" state. 20 | 21 | If an Improv service has been authorized by a user interaction, the authorization should be automatically revoked after a timeout. This timeout is up to the gadget but we suggest 1 minute. 22 | 23 | A user is able to send Wi-Fi credentials to an authorized service. The gadget will attempt to connect to the specified wireless network. If the connection is successful, the state changes to "provisioned", the gadget can optionally return a URL to the client to finish onboarding and the Improv service is stopped. 24 | 25 | If the gadget is unable to connect an error is returned. If the gadget required authorization, the authorization reset timeout should start over. 26 | 27 | ![Improv State machine](/images/improv-states.svg) 28 | 29 | The client is able to send an `identify` command to the Improv service if it is in the states "Require Authorization" and "Authorized". When received, and enabled, the gadget will identify itself, like playing a sound or flashing a light. It is up to the gadget to decide if and what interaction to pick. 30 | 31 | ## Revision history 32 | 33 | - 1.0 - Initial release 34 | - 2.0 - Added Service Data `4677` 35 | 36 | ## GATT Services 37 | 38 | ### Characteristic: Capabilities 39 | 40 | Characteristic UUID: `00467768-6228-2272-4663-277478268005` 41 | 42 | This characteristic has binary encoded byte(s) of the device’s capabilities. 43 | 44 | | Bit (LSB) | Capability | 45 | | --------- | ---------------------------------------------- | 46 | | `0` | 1 if the device supports the identify command. | 47 | 48 | ### Characteristic: Current State 49 | 50 | Characteristic UUID: `00467768-6228-2272-4663-277478268001` 51 | 52 | This characteristic will hold the current status of the provisioning service and will write and notify any listening clients for instant feedback. 53 | 54 | | Value | State | Purpose | 55 | | ------ | ---------------------- | ------------------------------------------------ | 56 | | `0x01` | Authorization Required | Awaiting authorization via physical interaction. | 57 | | `0x02` | Authorized | Ready to accept credentials. | 58 | | `0x03` | Provisioning | Credentials received, attempt to connect. | 59 | | `0x04` | Provisioned | Connection successful. | 60 | 61 | ### Characteristic: Error state 62 | 63 | Characteristic UUID: `00467768-6228-2272-4663-277478268002` 64 | 65 | This characteristic will hold the current error of the provisioning service and will write and notify any listening clients for instant feedback. 66 | 67 | | Value | State | Purpose | 68 | | ------ | ------------------- | --------------------------------------------------------------------------------------- | 69 | | `0x00` | No error | This shows there is no current error state. | 70 | | `0x01` | Invalid RPC packet | RPC packet was malformed/invalid. | 71 | | `0x02` | Unknown RPC command | The command sent is unknown. | 72 | | `0x03` | Unable to connect | The credentials have been received and an attempt to connect to the network has failed. | 73 | | `0x04` | Not Authorized | Credentials were sent via RPC but the Improv service is not authorized. | 74 | | `0xFF` | Unknown Error | 75 | 76 | ### Characteristic: RPC Command 77 | 78 | Characteristic UUID: `00467768-6228-2272-4663-277478268003` 79 | 80 | This characteristic is where the client can write data to call the RPC service. 81 | 82 | Note: if the combined payload is over 20 bytes, it will require multiple BLE packets to transfer the data. Make sure that your code deals with this. 83 | 84 | | Byte | Description | 85 | | ----- | ----------------------------------------------------- | 86 | | 1 | Command (see below) | 87 | | 2 | Data length | 88 | | 3...X | Data | 89 | | X + 3 | Checksum - A simple sum checksum keeping only the LSB | 90 | 91 | #### RPC Command: Send Wi-Fi settings 92 | 93 | Submit Wi-Fi credentials to the Improv Service to attempt to connect to. 94 | 95 | Requires the Improv service to be authorized. 96 | 97 | Command ID: `0x01` 98 | 99 | | Byte | Description | 100 | | ---- | --------------- | 101 | | 01 | command | 102 | | xx | data length | 103 | | yy | ssid length | 104 | | | ssid bytes | 105 | | zz | password length | 106 | | | password bytes | 107 | | CS | checksum | 108 | 109 | Example: SSID = MyWirelessAP, Password = mysecurepassword 110 | 111 | ``` 112 | 01 1E 0C {MyWirelessAP} 10 {mysecurepassword} CS 113 | ``` 114 | 115 | This command will generate an RPC result. The first entry in the list is an URL to redirect the user to. If there is no URL, omit the entry or add an empty string. 116 | 117 | #### RPC Command: Identify 118 | 119 | What a device actually does when an identify command is received is up to that specific device, but the user should be able to visually or audibly identify the device. 120 | 121 | Command ID: `0x02` 122 | 123 | Does not require the Improv service to be authorized. 124 | 125 | Should only be sent if the capability characteristic indicates that identify is supported. 126 | 127 | | Byte | Description | 128 | | ---- | ---------------------- | 129 | | 02 | command | 130 | | 00 | 0 data bytes / no data | 131 | | CS | checksum | 132 | 133 | This command has no RPC result. 134 | 135 | ### Characteristic: RPC Result 136 | 137 | Characteristic UUID: `00467768-6228-2272-4663-277478268004` 138 | 139 | This characteristic is where the client can read results from the RPC service if it has a result. Results are returned as a list of strings. An empty list is allowed. 140 | 141 | | Byte | Description | 142 | | --------- | ----------------------------------------------------- | 143 | | 1 | Command (see below) | 144 | | 2 | Data length | 145 | | 3 | Length of string 1 | 146 | | 4...X | String 1 | 147 | | X | Length of string 2 | 148 | | X...Y | String 2 | 149 | | ... | etc | 150 | | last byte | Checksum - A simple sum checksum keeping only the LSB | 151 | 152 | ## Bluetooth LE Advertisement 153 | 154 | The device MUST advertise the Service UUID. 155 | 156 | Service UUID: `00467768-6228-2272-4663-277478268000` 157 | 158 | With version 2.0 of the specification: 159 | 160 | - The Service Data and Service UUID MUST be advertised periodically and when the state changes. 161 | - The Service Data and Service UUID MUST be in the same advertisement. 162 | - The Service Data and Service UUID MUST NOT be in the scan response or require active scans. 163 | - If the device cannot fit all of its advertising data in 31 bytes, it should cycle between advertising data. 164 | 165 | ### Service Data format 166 | 167 | Service Data UUID: `4677` (`00004677-0000-1000-8000-00805f9b34fb`) 168 | 169 | | Byte | Description | 170 | | --------- | ----------------------------------------------------- | 171 | | 1 | Current state | 172 | | 2 | Capabilities | 173 | | 3 | 0 (RESERVED) | 174 | | 4 | 0 (RESERVED) | 175 | | 5 | 0 (RESERVED) | 176 | | 6 | 0 (RESERVED) | 177 | -------------------------------------------------------------------------------- /src/code.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: Code 4 | description: SDKs and code samples for Improv Wi-Fi clients and services. 5 | --- 6 | 7 | This page contains software development kits (SDK) and code samples to help you get started using Improv Wi-Fi in your projects. 8 | 9 | ## Creating client applications to configure devices 10 | 11 | These examples will help you create clients that can provision devices via Improv. 12 | 13 | ### Bluetooth LE SDK for JavaScript 14 | 15 | The Bluetooth LE SDK for JavaScript contains everything you need to offer Improv provisioning using Bluetooth LE on your website. Simply get started by adding the following HTML snippet: 16 | 17 | ```js 18 | 22 | 23 | 24 | ``` 25 | 26 | The result will look like this: 27 | 28 | > 29 | 30 | See [the GitHub repository](https://github.com/improv-wifi/sdk-js) for the documentation, source code, customization examples and how to use it with JavaScript package managers. 31 | 32 | ### Serial SDK for JavaScript 33 | 34 | The Serial SDK for JavaScript contains everything you need to offer Improv provisioning using Serial on your website. See [the GitHub repository](https://github.com/improv-wifi/sdk-serial-js) for the documentation, source code, customization examples and how to use it with JavaScript package managers. 35 | 36 | ### Bluetooth LE SDK for Android 37 | 38 | The Android SDK contains all state management, constants and other helpers required to provision devices via Improv. 39 | 40 | See [the GitHub repository](https://github.com/improv-wifi/sdk-android) for the documentation, source code and demo application. 41 | 42 | ## Creating firmware hosting the Improv service 43 | 44 | ### SDK for C++ 45 | 46 | The C++ SDK contains constants and utility functions to parse the packets and help with implementing the Improv service on your device. If you need an example of using the SDK for C++, check this example [here](https://jnthas.github.io/improv-wifi-demo/). 47 | 48 | See [the GitHub repository](https://github.com/improv-wifi/sdk-cpp) for the documentation and source code. 49 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | description: Free and open standard with ready-made SDKs that offer a great user experience to configure Wi-Fi on devices. 4 | --- 5 | 6 | 10 | 11 |

12 | Improv Wi-Fi is an open standard for connecting devices to Wi-Fi using Bluetooth LE or Serial 13 |

14 | 15 |

16 | Improv is a free and open standard with ready-made SDKs that offer a great 17 | user experience to configure Wi-Fi on devices: 18 |

19 |
    20 |
  1. Power on device
  2. 21 |
  3. 22 | Client application uses Improv to send the Wi-Fi credentials to the device 23 |
  4. 24 |
  5. The device connects to Wi-Fi network and returns a URL
  6. 25 |
  7. User visits URL to continue setting up the device
  8. 26 |
27 |

28 | Improv protocol can be used over Bluetooth Low Energy or via the serial port. 29 | Both protocols can also be used from a browser. 30 |

31 |
32 |

Improv via BLE

33 | 34 | 35 | Your browser is not supported. To try it out, visit this page with Google 36 | Chrome or Microsoft Edge. 39 | 40 | 41 |

Improv via Serial

42 | 43 | 44 | Your browser is not supported. To try it out, visit this page with Google 45 | Chrome or Microsoft Edge. 48 | 49 | 50 |
51 |

52 | 53 | Need a device that runs Improv? 54 | Install this example 55 | on an ESP32. 56 | 57 |

58 |

See it in action

59 |
60 | 64 |
65 | 66 |

Adopted by the following projects

67 | 68 |
69 | 70 | 73 |
WLED
74 |
75 | 80 | 83 |
Tasmota
84 |
85 | 86 | 89 |
ESPHome
90 |
91 | 96 | 99 |
ESP Web Tools
100 |
101 | 105 | 108 |
Clockwise
109 |
110 | 114 | 117 |
Luciferin
118 |
119 |
120 | 121 |

The problem we're solving

122 | 123 |

Configuring a device to connect to your Wi-Fi network is a pain.

124 | 125 |

126 | A lot of devices require to be connected to the network to be controlled or 127 | receive data. The majority of these devices use Wi-Fi to establish a 128 | connection with a local application or the cloud. 129 |

130 | 131 |

132 | The most common approach is Soft Enabled Access Point. The device starts its 133 | own Wi-Fi access point, the user connects to it with their phone/computer and 134 | then interacts directly with the device via an app or a website served from 135 | the device. 136 |

137 | 138 |

139 | It’s easy for something to go wrong. The user submits incorrect Wi-Fi 140 | credentials or the phone loses access to the access point. In such cases it is 141 | difficult to recover. Phones also have a bad time dealing with access points 142 | that don’t provide internet access. 143 |

144 | 145 |

Scope & Constraints

146 |

147 | The goal of the Improv standard is to get the device connected to the Wi-Fi 148 | via Bluetooth Low Energy (BLE) or Serial (USB/UART). It is not the goal to 149 | offer a way for devices to share data or control. The standard should work 150 | without requiring the device to contain a screen. 151 |

152 | 153 |

More Reading

154 | 155 | 162 | 163 | 177 | -------------------------------------------------------------------------------- /src/serial.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: base 3 | title: Improv via Serial 4 | description: 5 | --- 6 | 7 | This is the description of the Improv Wi-Fi protocol using a serial port. 8 | 9 | The device needs to be connected to the computer via a USB/UART serial port. 10 | 11 | The protocol has two actors: the Improv service running on the gadget and the Improv client. 12 | 13 | The Improv service will receive Wi-Fi credentials from the client via the serial connection. 14 | 15 | The Improv client asks for the current state and sends the Wi-Fi credentials. 16 | 17 | ## Packet format 18 | 19 | All packets are sent in the following format: 20 | 21 | | Byte | Purpose | 22 | | ------ | ------------------------------- | 23 | | 1-6 | Header will equal `IMPROV` | 24 | | 7 | Version CURRENT VERSION = `1` | 25 | | 8 | Type (see below) | 26 | | 9 | Length | 27 | | 10...X | Data | 28 | | X + 10 | Checksum | 29 | 30 | The packet types are: 31 | 32 | | Type | Description | Direction 33 | | ---- | ----------- | -------- 34 | | `0x01 ` | Current state | Device to Client 35 | | `0x02 ` | Error state | Device to Client 36 | | `0x03 ` | RPC Command | Client to Device 37 | | `0x04 ` | RPC Result | Device to Client 38 | 39 | ## Packet: Current State 40 | 41 | Type: `0x01`
42 | Direction: Device to Client 43 | 44 | The data of this packet is a single byte and contains the current status of the provisioning service. It is to be written to any listening clients for instant feedback. 45 | 46 | | Byte | Description | 47 | | ---- | ---------------- | 48 | | 1 | current state | 49 | 50 | The current state can be the following values: 51 | 52 | | Value | State | Purpose | 53 | | ------ | ---------------------- | ------------------------------------------------ | 54 | | `0x02` | Ready (Authorized) | Ready to accept credentials. | 55 | | `0x03` | Provisioning | Credentials received, attempt to connect. | 56 | | `0x04` | Provisioned | Connection successful. | 57 | 58 | 59 | ## Packet: Error state 60 | 61 | Type: `0x02`
62 | Direction: Device to client 63 | 64 | The data of this packet is a single byte and contains the current status of the provisioning service. Whenever it changes the device needs to sent it to any listening clients for instant feedback. 65 | 66 | | Byte | Description | 67 | | ---- | ---------------- | 68 | | 1 | error state | 69 | 70 | Error state can be the following values: 71 | 72 | | Value | State | Purpose | 73 | | ------ | ------------------- | --------------------------------------------------------------------------------------- | 74 | | `0x00` | No error | This shows there is no current error state. | 75 | | `0x01` | Invalid RPC packet | RPC packet was malformed/invalid. | 76 | | `0x02` | Unknown RPC command | The command sent is unknown. | 77 | | `0x03` | Unable to connect | The credentials have been received and an attempt to connect to the network has failed. | 78 | | `0xFF` | Unknown Error | | 79 | 80 | ## Packet: RPC Command 81 | 82 | Type: `0x03`
83 | Direction: Client to device 84 | 85 | This packet type is used for the client to send commands to the device. When an RPC command is sent, the device should sent an update to the client to set the error state to 0 (no error). The response will either be an RPC result packet or an error state update. 86 | 87 | | Byte | Description | 88 | | ----- | ----------------------------------------------------- | 89 | | 1 | Command (see below) | 90 | | 2 | Data length | 91 | | 3...X | Data | 92 | 93 | ### RPC Command: Send Wi-Fi settings 94 | 95 | Submit Wi-Fi credentials to the Improv Service to attempt to connect to. 96 | 97 | Type: `0x03`
98 | Command ID: `0x01` 99 | 100 | | Byte | Description | 101 | | ----- | ---------------- | 102 | | 1 | command (`0x01`) | 103 | | 2 | data length | 104 | | 3 | ssid length | 105 | | 4...X | ssid bytes | 106 | | X | password length | 107 | | X...Y | password bytes | 108 | 109 | Example: SSID = MyWirelessAP, Password = mysecurepassword 110 | 111 | ``` 112 | 01 1E 0C {MyWirelessAP} 10 {mysecurepassword} 113 | ``` 114 | 115 | This command will generate an RPC result. The first entry in the list is an URL to redirect the user to. If there is no URL, omit the entry or add an empty string. 116 | 117 | ### RPC Command: Request current state 118 | 119 | Sends a request for the device to send the current state of improv to the client. 120 | 121 | Type: `0x03`
122 | Command ID: `0x02` 123 | 124 | | Byte | Description | 125 | | ---- | ---------------- | 126 | | 1 | command (`0x02`) | 127 | | 2 | data length (`0`)| 128 | 129 | This command will trigger at least one packet, the `Current State` (see above) and if already provisioned, the same response you would get if device provisioning was successful (see below). 130 | 131 | ### RPC Command: Request device information 132 | 133 | Sends a request for the device to send information about itself. 134 | 135 | Type: `0x03`
136 | Command ID: `0x03` 137 | 138 | | Byte | Description | 139 | | ---- | ---------------- | 140 | | 1 | command (`0x03`) | 141 | | 2 | data length (`0`)| 142 | 143 | This command will trigger one packet, the `Device Information` formatted as a RPC result. This result will contain at least 4 strings. 144 | 145 | Order of strings: Firmware name, firmware version, hardware chip/variant, device name. 146 | 147 | Example: `ESPHome`, `2021.11.0`, `ESP32-C3`, `Temperature Monitor`. 148 | 149 | ### RPC Command: Request scanned Wi-Fi networks 150 | 151 | Sends a request for the device to send the Wi-Fi networks it sees. 152 | 153 | Type: `0x03`
154 | Command ID: `0x04` 155 | 156 | | Byte | Description | 157 | | ---- | ---------------- | 158 | | 1 | command (`0x04`) | 159 | | 2 | data length (`0`)| 160 | 161 | This command will trigger at least one RPC Response. Each response will contain at least 3 strings. 162 | 163 | Order of strings: Wi-Fi SSID, RSSI, Auth required. 164 | 165 | Example: `MyWirelessNetwork`, `-60`, `YES`. 166 | 167 | The final response (or the first if no networks are found) will have 0 strings in the body. 168 | 169 | ## Packet: RPC Result 170 | 171 | Type: `0x04`
172 | Direction: Device to client 173 | 174 | This packet type contains the response to an RPC command. Results are returned as a list of strings. An empty list is allowed. 175 | 176 | | Byte | Description | 177 | | --------- | ----------------------------------------------------- | 178 | | 1 | Command being responded to (see above) | 179 | | 2 | Data length | 180 | | 3 | Length of string 1 | 181 | | 4...X | String 1 | 182 | | X | Length of string 2 | 183 | | X...Y | String 2 | 184 | | ... | etc | 185 | --------------------------------------------------------------------------------