improv.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #pragma once
  2. // This is the description of the Improv Wi-Fi protocol using a serial port.
  3. // The device needs to be connected to the computer via a USB/UART serial port.
  4. // The protocol has two actors: the Improv service running on the gadget and the Improv client.
  5. // The Improv service will receive Wi-Fi credentials from the client via the serial connection.
  6. // The Improv client asks for the current state and sends the Wi-Fi credentials.
  7. // =========================================================================================
  8. // Packet format
  9. // ======================================
  10. // Byte Purpose
  11. // ---- -------------------------------
  12. // 1-6 Header will equal IMPROV
  13. // 7 Version CURRENT VERSION = 1
  14. // 8 Type (see below)
  15. // 9 Length
  16. // 10...X Data
  17. // X + 10 Checksum
  18. // =========================================================================================
  19. // Packet types
  20. // ======================================
  21. // Type Description Direction
  22. // ---- ------------ -----------------
  23. // 0x01 Current state Device to Client
  24. // 0x02 Error state Device to Client
  25. // 0x03 RPC Command Device to Client
  26. // 0x04 RPC Result Client to Device
  27. typedef enum {
  28. IMPROV_PACKET_TYPE_CURRENT_STATE = 0x01,
  29. IMPROV_PACKET_TYPE_ERROR_STATE = 0x02,
  30. IMPROV_PACKET_TYPE_RPC = 0x03,
  31. IMPROV_PACKET_TYPE_RPC_RESPONSE = 0x04
  32. } ImprovSerialType_t;
  33. // =========================================================================================
  34. // Packet: Current State
  35. // ======================================
  36. // Type: 0x01
  37. // Direction: Device to Client
  38. // --------------------------------------
  39. // The data of this packet is a single byte and contains the current status of the provisioning
  40. // service. It is to be written to any listening clients for instant feedback.
  41. // Byte Description
  42. // 1 current state
  43. // The current state can be the following values:
  44. // Value State Purpose
  45. // ----- ------------------ -----------------------------------------
  46. // 0x02 Ready (Authorized) Ready to accept credentials.
  47. // 0x03 Provisioning Credentials received, attempt to connect.
  48. // 0x04 Provisioned Connection successful.
  49. typedef enum {
  50. IMPROV_STATE_READY_AUTHORIZED = 0x02,
  51. IMPROV_STATE_PROVISIONING = 0x03,
  52. IMPROV_STATE_PROVISIONED = 0x04,
  53. } ImprovState_t;
  54. // =========================================================================================
  55. // Packet: Error state
  56. // ======================================
  57. // Type: 0x02
  58. // Direction: Device to client
  59. // --------------------------------------
  60. // The data of this packet is a single byte and contains the current status of the
  61. // provisioning service. Whenever it changes the device needs to sent it to any listening
  62. // clients for instant feedback.
  63. // Byte Description
  64. // 1 error state
  65. // Error state can be the following values:
  66. // Value State Purpose
  67. // ----- ------------------ -----------------------------------------
  68. // 0x00 No error This shows there is no current error state.
  69. // 0x01 Invalid RPC packet RPC packet was malformed/invalid.
  70. // 0x02 Unknown RPC command The command sent is unknown.
  71. // 0x03 Unable to connect The credentials have been received and an attempt to connect
  72. // to the network has failed.
  73. // 0xFF Unknown Error
  74. typedef enum {
  75. IMPROV_ERROR_NONE = 0x00,
  76. IMPROV_ERROR_INVALID_RPC = 0x01,
  77. IMPROV_ERROR_UNKNOWN_RPC = 0x02,
  78. IMPROV_ERROR_UNABLE_TO_CONNECT = 0x03,
  79. IMPROV_ERROR_NOT_AUTHORIZED = 0x04,
  80. IMPROV_ERROR_UNKNOWN = 0xFF,
  81. } ImprovError_t;
  82. // =========================================================================================
  83. // Packet: RPC Command
  84. // Type: 0x03
  85. // Direction: Client to device
  86. // --------------------------------------
  87. // This packet type is used for the client to send commands to the device. When an RPC
  88. // command is sent, the device should sent an update to the client to set the error state to
  89. // 0 (no error). The response will either be an RPC result packet or an error state update.
  90. // Byte Description
  91. // ----- ---------------------
  92. // 1 Command (see below)
  93. // 2 Data length
  94. // 3...X Data
  95. typedef enum {
  96. IMPROV_CMD_UNKNOWN = 0x00,
  97. IMPROV_CMD_WIFI_SETTINGS = 0x01,
  98. IMPROV_CMD_GET_CURRENT_STATE = 0x02,
  99. IMPROV_CMD_GET_DEVICE_INFO = 0x03,
  100. IMPROV_CMD_GET_WIFI_NETWORKS = 0x04,
  101. IMPROV_CMD_BAD_CHECKSUM = 0xFF,
  102. } ImprovCommand_t;
  103. // ======================================
  104. // RPC Command: Send Wi-Fi settings
  105. // Submit Wi-Fi credentials to the Improv Service to attempt to connect to.
  106. // Type: 0x03
  107. // Command ID: 0x01
  108. // Byte Description
  109. // ----- ----------------
  110. // 1 command (0x01)
  111. // 2 data length
  112. // 3 ssid length
  113. // 4...X ssid bytes
  114. // X password length
  115. // X...Y password bytes
  116. // Example: SSID = MyWirelessAP, Password = mysecurepassword
  117. // 01 1E 0C {MyWirelessAP} 10 {mysecurepassword}
  118. // This command will generate an RPC result. The first entry in the list is an URL to
  119. // redirect the user to.
  120. // If there is no URL, omit the entry or add an empty string.
  121. // ======================================
  122. // RPC Command: Request current state
  123. // Sends a request for the device to send the current state of improv to the client.
  124. // Type: 0x03
  125. // Command ID: 0x02
  126. // Byte Description
  127. // ----- ----------------
  128. // 1 command (0x02)
  129. // 2 data length (0)
  130. // This command will trigger at least one packet, the Current State (see above) and if
  131. // already provisioned,
  132. // the same response you would get if device provisioning was successful (see below).
  133. // ======================================
  134. // RPC Command: Request device information
  135. // Sends a request for the device to send information about itself.
  136. // Type: 0x03
  137. // Command ID: 0x03
  138. // Byte Description
  139. // ----- ----------------
  140. // 1 command (0x02)
  141. // 2 data length (0)
  142. // This command will trigger one packet, the Device Information formatted as a RPC result.
  143. // This result will contain at least 4 strings.
  144. // Order of strings: Firmware name, firmware version, hardware chip/variant, device name.
  145. // Example: ESPHome, 2021.11.0, ESP32-C3, Temperature Monitor.
  146. // ======================================
  147. // RPC Command: Request scanned Wi-Fi networks
  148. // Sends a request for the device to send the Wi-Fi networks it sees.
  149. // Type: 0x03
  150. // Command ID: 0x04
  151. // Byte Description
  152. // ----- ----------------
  153. // 1 command (0x02)
  154. // 2 data length (0)
  155. // This command will trigger at least one RPC Response. Each response will contain at
  156. // least 3 strings.
  157. // Order of strings: Wi-Fi SSID, RSSI, Auth required.
  158. // Example: MyWirelessNetwork, -60, YES.
  159. // The final response (or the first if no networks are found) will have 0 strings in the body.
  160. // =========================================================================================
  161. // Packet: RPC Result
  162. // ======================================
  163. // Type: 0x04
  164. // Direction: Device to client
  165. // --------------------------------------
  166. // This packet type contains the response to an RPC command. Results are returned as a list
  167. // of strings. An empty list is allowed.
  168. // Byte Description
  169. // ----- ----------------
  170. // 1 Command being responded to (see above)
  171. // 2 Data length
  172. // 3 Length of string 1
  173. // 4...X String 1
  174. // X Length of string 2
  175. // X...Y String 2
  176. // ... etc
  177. static const uint8_t CAPABILITY_IDENTIFY = 0x01;
  178. static const uint8_t IMPROV_SERIAL_VERSION = 1;
  179. #ifndef FREE_AND_NULL
  180. #define FREE_AND_NULL(x) if(x) { free(x); x=NULL; }
  181. #endif
  182. #ifndef ENUM_TO_STRING
  183. #define ENUM_TO_STRING(g) \
  184. case g: \
  185. return STR(g); \
  186. break;
  187. #endif
  188. typedef struct {
  189. ImprovCommand_t command;
  190. char * ssid;
  191. char * password;
  192. } ImprovCommandStruct_t;
  193. typedef struct {
  194. char * ssid;
  195. char * rssi;
  196. char * auth_req; // YES/NO
  197. } ImprovAPListStruct_t;
  198. #define IMPROV_AP_STRUCT_NUM_STR 3
  199. typedef struct {
  200. char * firmware_name;
  201. char * firmware_version;
  202. char * hardware_chip_variant;
  203. char * device_name;
  204. char * nullptr;
  205. } ImprovDeviceInfoStruct_t;
  206. #define IMPROV_DEVICE_INFO_NUM_STRINGS 4
  207. typedef bool (*improv_command_callback_t)(ImprovCommandStruct_t *cmd);
  208. typedef void (*on_error_callback_t)(ImprovError_t error);
  209. typedef bool (*improv_send_callback_t)(uint8_t * buffer, size_t length);
  210. typedef struct {
  211. int index ;
  212. improv_command_callback_t callback ;
  213. } callback_table_t;
  214. void improv_parse_data(ImprovCommandStruct_t * improv_command, const uint8_t *data, size_t length, bool check_checksum) ;
  215. bool improv_parse_serial_byte(size_t position, uint8_t byte, const uint8_t *buffer,improv_command_callback_t callback, on_error_callback_t on_error);
  216. bool parse_improv_serial_line( const uint8_t *buffer);
  217. void improv_set_send_callback(improv_send_callback_t callback );
  218. bool improv_set_callback(ImprovCommand_t command, improv_command_callback_t callback );
  219. bool improv_wifi_list_allocate(size_t num_entries);
  220. bool improv_wifi_list_add(const char * ssid, int8_t rssi, bool auth_req );
  221. bool improv_wifi_list_send( );
  222. size_t improv_wifi_get_wifi_list_count();
  223. bool improv_send_device_info( const char * firmware_name, const char * firmware_version, const char * hardware_chip_variant, const char * device_name);
  224. uint8_t * improv_build_response(ImprovSerialType_t command, const char * datum, size_t len, size_t * out_len);
  225. uint8_t * improv_build_rpc_response(ImprovCommand_t command, const char ** results, size_t num_strings, size_t * out_len);
  226. bool improv_send_current_state(ImprovState_t state);
  227. bool improv_send_error(ImprovError_t error);
  228. const char * improv_get_error_desc(ImprovError_t error);
  229. const char * improv_get_command_desc(ImprovCommand_t command);
  230. bool improv_send_device_url( ImprovCommand_t from_command, const char * url);
  231. // Improv Wi-Fi – Contact – GitHub
  232. // Improv is an initiative by ESPHome & Home Assistant.
  233. // Development funded by Nabu Casa.