1. 當使用Mode 3 (STA+ SoftAP)時,STA無法連進SoftAP。
2.SoftAP 預設只能夠有4個裝置連入,多的就連不上了,但其實他的極限是8個,
只是必須去改config檔,以下是官網的原文
ESP8266 soft-AP can connected to 8 stations at most,
softap_config.max_connection default is 4
http://bbs.espressif.com/viewtopic.php?t=1894
3.SoftAP 本身就是這一個網域的一份子,可以透過UART要求傳連線及資料給網域中的
其他Client。
4. Mode 3時,STA和SoftAP會在同一個Wi-Fi Channel 中 。(Wi-Fi 有13個Channel)
2016年8月12日 星期五
2016年8月11日 星期四
「ESP8266」Non-OS SDK V.S RTOS SDK
一開始在找Firmware檔案時,發現有二種SDK,找了一些資料才明白差異,紀錄一下。
1. Non-OS SDK
Non-OS SDK 是不基於OS的 SDK,提供 IOT_Demo 和 AT 的編譯。
Non-OS SDK 主要使用定時器和回調函數的方式實現各個功能事件的嵌套,
達到特定條件下觸發特定功能函數的目的。Non-OS SDK 使用 espconn 接口
實現網路操作,使用者需要按照 espconn 接口的使用規則進行軟件開發。
如果要透過AT Command,請燒錄這個SDK。
2. RTOS SDK
RTOS SDK 基於 FreeRTOS,在 Github 上開源。
* RTOS 版本 SDK 使用 FreeRTOS 系統,引入 OS 多任務處理的機制,用戶可以使用
FreeRTOS 的標准接口實現資源管理、循環操作、任務內延時、任務間信息傳遞和同步等面
向任務流程的設計方式。
* RTOS 版本 SDK 的網路操作提供了 BSD Socket API 接口的封裝實現,
使用者可以直接按照 Socket API 的使用方式來開發軟件應用,
也可以直接編譯運行其他平台的標准 Socket 應用,有效降低平台切換的學習成本。
* RTOS 版本 SDK 引入了 cJSON 庫,可以更加方便的實現對 JSON 數據包的解析。
* RTOS 版本相容 Non-OS SDK 中的 Wi-Fi 接口、Smart Config 接口、
Sniffer 相關接口、系統接口、定時器接口、FOTA 接口和外圍驅動接口,不支持 AT 實現。
[EPS8266] 回復AT Command 功能
當你用Arduino燒錄程式後,你會發現,EPS8266 不再回應你的AT COMMAND了。
沒錯,的確如此,因為AT COMMAND的功能被你的Arduino code取代了。
後來我找到方式,其實是可以燒回去的,首先你要找到AT Command Firmware檔。
http://bbs.espressif.com/viewtopic.php?f=46&t=1451
版本 ESP8266_AT_v0.51 基于 ESP8266_NONOS_SDK_V1.5.0
使用這一版本Firmware注意一件事,必須使用新版的ESP8266-01 ,通常是黑色底版。
接著等待它跑
整個過程大約30秒。
如果一直顯示無法連接ESP8266,先確認線是否有接好,尤其是GPIO0 必須為GND。
如果還是失敗,先將ESP8266 斷電,重新RUN一次指令,等connecting..出現時立刻上電。
應該這樣幾次就會成功了,建議使用有開關的麵包板供電模組,不要直接用Usb To TTL供電。
沒錯,的確如此,因為AT COMMAND的功能被你的Arduino code取代了。
後來我找到方式,其實是可以燒回去的,首先你要找到AT Command Firmware檔。
http://bbs.espressif.com/viewtopic.php?f=46&t=1451
版本 ESP8266_AT_v0.51 基于 ESP8266_NONOS_SDK_V1.5.0
使用這一版本Firmware注意一件事,必須使用新版的ESP8266-01 ,通常是黑色底版。
從當前版本 ESP8266_AT_v0.51 起,AT 固件所需空間增大,無法再使用 4Mbit (512KB) Flash,請使用 8Mbit (1MB) 或以上容量 Flash。
下載下來並解壓縮,內容會如下所示
進入bin才是我們要的內容
接下來開啟readme.txt,會告訴你每一種不容量的版子,你需要燒錄什麼檔案在什麼位置
以ESP8266-01來看,就是8Mbit(1MB) 512k+512k
燒錄指令如下(需要先入手esptool工具https://github.com/themadinventor/esptool)
燒錄指令如下(需要先入手esptool工具https://github.com/themadinventor/esptool)
sudo esptool.py -p /dev/cu.SLAB_USBtoUART -b 115200 write_flash 0x00000 boot_v1.6.bin 0x01000 ESP8266_NONOS_SDK/bin/at/512+512/user1.1024.new.2.bin 0xfc000 ESP8266_NONOS_SDK/bin/esp_init_data_default.bin 0x7e000 ESP8266_NONOS_SDK/bin/blank.bin
接著等待它跑
esptool.py v1.0.1 Connecting... Erasing flash... Took 0.13s to erase flash block Wrote 4096 bytes at 0x00000000 in 0.4 seconds (81.1 kbit/s)... Erasing flash... Took 2.60s to erase flash block Wrote 419840 bytes at 0x00001000 in 41.0 seconds (81.9 kbit/s)... Erasing flash... Took 0.09s to erase flash block Wrote 1024 bytes at 0x000fc000 in 0.1 seconds (85.2 kbit/s)... Erasing flash... Took 0.15s to erase flash block Wrote 4096 bytes at 0x0007e000 in 0.4 seconds (85.4 kbit/s)... Leaving...
整個過程大約30秒。
如果一直顯示無法連接ESP8266,先確認線是否有接好,尤其是GPIO0 必須為GND。
如果還是失敗,先將ESP8266 斷電,重新RUN一次指令,等connecting..出現時立刻上電。
應該這樣幾次就會成功了,建議使用有開關的麵包板供電模組,不要直接用Usb To TTL供電。
2016年8月1日 星期一
「Android」Mattermost Android 遇到 Self-signed certificate 解法
Mattermost Android版在遇到SSL使用Self-signed certificate 時, 會無法連接,
解決方法:
到這裡下載原始碼開始Debug,一開始什麼都不改,先來看到底
登入時跳出的exception為
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
看了CODE之後發現,由於Mattermost的HTTP 是透過Okhttp 這個套件,
所以不能輕易的叫他吞下去當做沒看到。
換個方式,既然certification path not found. 我們就指定給它。
(1)首先我們要把Self-signed certificate放到專案中的raw資料夾
接下來在MattermostService.java中新增一個setCertificates函式,
用來將我們放在raw資料夾中的憑證指定給 Okhttp Client
public void setCertificates(InputStream... certificates) { try { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); int index = 0; for (InputStream certificate : certificates) { String certificateAlias = Integer.toString(index++); keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); try { if (certificate != null) certificate.close(); } catch (IOException e) { } } SSLContext sslContext = SSLContext.getInstance("TLS"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); sslContext.init ( null, trustManagerFactory.getTrustManagers(), new SecureRandom() ); client.setSslSocketFactory(sslContext.getSocketFactory()); } catch (Exception e) { e.printStackTrace(); } }
接下來修改MattermostService.java建構子,
新增一行呼叫setCertificates來讀取self cert
//add self cert setCertificates(context.getResources().openRawResource(R.raw.nginx));
public MattermostService(Context context) { this.context = context; String userAgent = context.getResources().getString(R.string.app_user_agent); cookieStore = new WebkitCookieManagerProxy(); client.setCookieHandler(cookieStore); //add self cert setCertificates(context.getResources().openRawResource(R.raw.nginx)); preferences = context.getSharedPreferences("App", Context.MODE_PRIVATE); }
到這裡, 你己經可以登入了, 但是會發現白白的一片, 因為還需要修改WebView SSL Error
的情況, 修改一下MainActivity.java
找到protected void setWebViewClient(WebView view)
增加一段處理SSL Error的程式碼
@Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { // super.onReceivedSslError(view, handler, error);
handler.proceed(); }
protected void setWebViewClient(WebView view) { view.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { dialog.hide(); Log.i("onPageFinished", "onPageFinished while loading"); Log.i("onPageFinished", url); if (url.equals("about:blank")) { AlertDialog.Builder alert = new AlertDialog.Builder(MainActivity.this); alert.setTitle(R.string.error_retry); alert.setPositiveButton(R.string.error_logout, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { MainActivity.this.onLogout(); } }); alert.setNegativeButton(R.string.error_refresh, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { MainActivity.this.loadRootView(); } }); alert.show(); } } @Override public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) { Log.e("onReceivedHttpError", "onReceivedHttpError while loading"); StringBuilder total = new StringBuilder(); if (errorResponse.getData() != null) { BufferedReader r = new BufferedReader(new InputStreamReader(errorResponse.getData())); String line; try { while ((line = r.readLine()) != null) { total.append(line); } } catch (IOException e) { total.append("failed to read data"); } } else { total.append("no data"); } Log.e("onReceivedHttpError", total.toString()); } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { // super.onReceivedSslError(view, handler, error); handler.proceed(); } @Override public void onReceivedError (WebView view, int errorCode, String description, String failingUrl) { Log.e("onReceivedErrord", "onReceivedError while loading (d)"); Log.e("onReceivedErrord", errorCode + " " + description + " " + failingUrl); webView.loadUrl("about:blank"); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { Uri uri = Uri.parse(url); // Do not open in other browser if gitlab if (uri.getPath().contains("/oauth/authorize")) { return false; } // Do not open in other browser if gitlab if (uri.getPath().contains("/oauth/token")) { return false; } // Do not open in other browser if gitlab if (uri.getPath().contains("/api/v3/user")) { return false; } // Do not open in other browser if gitlab if (uri.getPath().contains("/users/sign_in")) { return false; } if (!uri.getHost().equalsIgnoreCase(appUri.getHost())) { openUrl(uri); return true; } if (uri.getPath().startsWith("/static/help")) { openUrl(uri); return true; } if (uri.getPath().contains("/files/get/")) { openUrl(uri); return true; } return super.shouldOverrideUrlLoading(view, url); } @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { // Check to see if we need to attach the device Id if (url.toLowerCase().contains("/channels/")) { if (!MattermostService.service.isAttached()) { Log.i("MainActivity", "Attempting to attach device id"); MattermostService.service.init(MattermostService.service.getBaseUrl()); Promise<User> p = MattermostService.service.attachDevice(); if (p != null) { p.then(new IResultListener<User>() { @Override public void onResult(Promise<User> promise) { if (promise.getError() != null) { Log.e("AttachDeviceId", promise.getError()); } else { Log.i("AttachDeviceId", "Attached device_id to session"); MattermostService.service.SetAttached(); } } }); } } } // Check if deviceID is missing if (url.toLowerCase().contains("/login")) { MattermostService.service.SetAttached(false); } // Check to see if the user was trying to logout if (url.toLowerCase().endsWith("/logout")) { MattermostApplication.handler.post(new Runnable() { @Override public void run() { onLogout(); } }); } return super.shouldInterceptRequest(view, url); } }); }
透過以上的修改後, Android版就可以正常登入Self-signed certificate 的Mattermost網頁
訂閱:
文章 (Atom)