FOTA – tức Firmware Over-The-Air là 1 cơ chế giúp bạn nạp chương trình cho esp8266 từ xa qua mạng wifi mà không cần cắm vào máy tính
Hãy thử tưởng tượng khi bạn bán ra hàng trăm sản phẩm IoT cho khách hàng và bất ngờ phát hiện chương trình gặp 1 lỗi nhỏ. Bạn không thể thu hồi lại mạch để nạp lại chương trình mới cho khách được, việc này qua tốn kém. Thay vào đó, chỉ cần upload chương trình đã fix lỗi lên server để tất cả các thiết bị tự động cập nhật code mới ! Thật tiện lợi phải không 😀
Cách hoạt động
Khi esp8266 khởi động và kết nối vào wifi, nó sẽ gửi đi 1 truy vấn tới server của bạn kèm theo phiên bản phần mềm nó đang có. Server kiểm tra và so sánh nếu phần mềm này đã lỗi thời thì gửi file code mới xuống cho esp8266 để nó tự cập nhật chương trình cho chính nó
Lưu ý: Trong code mới cũng phải có chức năng FOTA cho lần cập nhật sau, nếu không bạn sẽ chỉ cập nhật được 1 lần rồi thôi
File code cho esp8266 sau khi biên dịch từ arduino ide có đuổi .bin
Để lấy file này thì ở Arduino IDE, các bạn vào File -> PreFerencs rồi tích vào compilation
Bây giờ khi ấn biên dịch, đường dẫn tới file code sẽ hiện ra ở đây
Các bạn theo đường dẫn này sẽ tới thư mục chưa file .bin
Mẹo: Copy đường dẫn ở arduino ide, sau đó xóa gạch chéo thừa đi rồi dán vào ô tìm kiếm thư mục cho nhanh
Lập trình chức năng FOTA
Như đã nói ở trên, trong code của các bạn ở hàm setup, chúng ta sẽ chèn thêm 1 đoạn chương trình OTA có nhiệm vụ kiểm tra trên server xem có cần cập nhật không.
Về phần server thì trong demo này mình sẽ sử dụng dịch vụ của 000webhost, 1 trang web cung cấp server free. Đương nhiên đây chỉ là server thử nghiệm, khi các bạn làm thương mại chắc chắn sẽ phải thuê hosting hoặc vps riêng cho ổn định
Sau khi đăng kí tải khoản mình đã tạo được trang web free tên là http://demo-ota.000webhostapp.com/
Các bạn vào phần quản lí website – > quản lí file để vào giao diện quản lí file. Ở đây chúng ta sẽ upload file code .bin và 1 đoạn chương trình php nho nhỏ để gửi file .bin xuống cho esp8266
Các bạn click vào thư mục public.html và tạo 1 file tên là index.php rồi dán đoạn code này vô
1 2 3 4 5 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 48 49 50 51 |
<?PHP /*Chương trình cập nhật firmwave qua internet cho phần cứng Writer: Dao Nguyen Email: daonguyen20798@gmail.com Phone: 0394733311 */ $VS = "2_0"; //mã phiên bản header('Content-type: text/plain; charset=utf8', true); function check_header($name, $value = false) { if(!isset($_SERVER[$name])) { return false; } if($value && $_SERVER[$name] != $value) { return false; } return true; } if(!check_header('HTTP_USER_AGENT', 'ESP8266-http-Update')) { header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403); echo "Chỉ phục vụ esp8266!"; exit(); } if( !check_header('HTTP_X_ESP8266_STA_MAC') || !check_header('HTTP_X_ESP8266_AP_MAC') || !check_header('HTTP_X_ESP8266_AP_MAC') || !check_header('HTTP_X_ESP8266_SKETCH_SIZE') || !check_header('HTTP_X_ESP8266_SKETCH_MD5') || !check_header('HTTP_X_ESP8266_CHIP_SIZE') || !check_header('HTTP_X_ESP8266_SDK_VERSION') ) { header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403); echo "Chỉ phục vụ esp8266!"; exit(); } //kiểm tra phiên bản if(check_header('HTTP_X_ESP8266_VERSION', $VS)) { header($_SERVER["SERVER_PROTOCOL"].' 403 Forbidden', true, 403); echo "no update"; exit(); } function sendFile($path) { header($_SERVER["SERVER_PROTOCOL"].' 200 OK', true, 200); header('Content-Type: application/octet-stream', true); header('Content-Disposition: attachment; filename='.basename($path)); header('Content-Length: '.filesize($path), true); header('x-MD5: '.md5_file($path), true); readfile($path); } sendFile( $VS . ".bin"); |
Giải thích code PHP:
Khi 1 thiết bị truy cập vào website của mình, tức http://demo-ota.000webhostapp.com/ nó sẽ gửi lên kèm 1 đoạn thông tin ( được gọi là header) để server biết nó là ai. lúc này trên server, file index.php sẽ được chạy, nó sẽ kiểm tra các request header để xem thiết bị truy cập kia có phải là esp8266 không, nếu sai thì nó sẽ in ra dòng Chỉ phục vụ esp8266! với mã lỗi 403 rồi thoát mà không làm gì cả.
Khi đã chắc chắn thiết bị truy cập vào server là esp8266, chúng ta sẽ tiếp tục kiểm tra xem phiên bản mà esp8266 đang có là gì. nếu không giống với phiên bản mới nhất trên server thì sẽ gửi file code .bin xuống kèm mã code 200 OK. Ngược lại thì gửi mã lỗi 403 để báo cho esp không cần phải cập nhật
Biến $VS = “2_0” báo rằng trên server đang có phiên bản “2_0”
Code cho esp8266
1 2 3 4 5 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 48 |
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <ESP8266httpUpdate.h> #define FW_VISION "1_0" //phiên bản của code char *wifi="your wifi"; //sửa thành wifi cải bạn char *pass="your pass"; //sửa thành pass wifi của bạn String server = "http://demo-ota.000webhostapp.com"; void setup() { Serial.begin(115200); Serial.println(); Serial.print("Connected to:"); Serial.println(wifi); WiFi.begin(wifi, pass); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("Connected with IP: "); Serial.println(WiFi.localIP()); Serial.println(); Serial.println("Check update ..."); t_httpUpdate_return ret = ESPhttpUpdate.update(server,FW_VISION); switch (ret) { case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break; case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break; } //-----------------your code---------------------- } void loop() { Serial.println("Đây là code phiên bản 1"); delay(5000); } |
Các bạn hãy đổi các thông tin wifi, server thành của bạn và nạp chương trình xuống cho esp8266
Bây giờ chúng ta sẽ tạo ra phiên bản code thứ 2 để lấy file .bin rồi tải lên server. File code v2 này mình chỉ biên dịch để lấy file code .bin chứ không nạp xuống nhé
1 2 3 4 5 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 48 |
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <ESP8266httpUpdate.h> #define FW_VISION "2_0" //phiên bản của code char *wifi="your wifi"; //sửa thành wifi cải bạn char *pass="your pass"; //sửa thành pass wifi của bạn String server = "http://demo-ota.000webhostapp.com"; void setup() { Serial.begin(115200); Serial.println(); Serial.print("Connected to:"); Serial.println(wifi); WiFi.begin(wifi, pass); while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("Connected with IP: "); Serial.println(WiFi.localIP()); Serial.println(); Serial.println("Check update ..."); t_httpUpdate_return ret = ESPhttpUpdate.update(server,FW_VISION); switch (ret) { case HTTP_UPDATE_FAILED: Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); break; case HTTP_UPDATE_NO_UPDATES: Serial.println("HTTP_UPDATE_NO_UPDATES"); break; case HTTP_UPDATE_OK: Serial.println("HTTP_UPDATE_OK"); break; } //-----------------your code---------------------- } void loop() { Serial.println("Đây là code phiên bản 2"); delay(5000); } |
Bây giờ mình sẽ đổi tên file .bin mà arduino ide sinh ra thành 2_0.bin ( phần tên này trùng với cái biến $SV trong code PHP
Sau đó upload lên server ( cùng vị trí với file index.php nhé)
Rồi bây giờ esp của chúng ta đang chạy code bản 1_0, mình sẽ ấn reset và cho esp8266 khởi động lại, nó sẽ truy cập vào server và gửi lên thông tin dạng “tôi là esp8266, tôi đang dùng phiên bản 1_0″
Server lúc này sẽ kiểm tra và thấy nó đang có phiên bản 2_0 nên nó sẽ gửi file 2_0.bin về cho esp8266 cập nhật code mới
Lần reset tiếp theo thì esp8266 đã có số phiên bản trùng với trên server nên nó sẽ không load code lại nữa và sẽ nhảy vào chương trình chính của các bạn
Cho anh hỏi trang web được tạo với wordpress đã thuê hosting và Domain có Upload được file code lên để cập nhật từ xa không nhỉ?
cho em xin link thư viện với
thế mỗi lần muốn esp cập nhật code mới lại phải reset à