├── settings.gradle
├── app
├── build.gradle
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ └── layout
│ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── smartconfig
│ │ ├── MainActivity.java
│ │ └── UdpThread.java
└── app.iml
└── gradle
└── wrapper
└── gradle-wrapper.properties
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 16
5 | buildToolsVersion "21.1.2"
6 | }
7 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SmartConfig
4 | SSID:
5 | Password:
6 | MQTT Host:
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
17 |
18 |
21 |
22 |
23 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
25 |
26 |
27 |
28 |
29 |
39 |
40 |
49 |
50 |
60 |
61 |
70 |
71 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/smartconfig/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015
5 | Stijn van Drunen (www.stijnvandrunen.nl),
6 | younger (https://github.com/youngBuger/esp8266-smartconfig)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 | */
26 |
27 | package com.example.smartconfig;
28 |
29 | import android.app.Activity;
30 | import android.app.AlertDialog;
31 | import android.net.wifi.WifiInfo;
32 | import android.net.wifi.WifiManager;
33 | import android.os.Bundle;
34 | import android.util.Log;
35 | import android.view.Menu;
36 | import android.view.View;
37 | import android.view.View.OnClickListener;
38 | import android.widget.Button;
39 | import android.widget.EditText;
40 |
41 | import com.example.smartlink.R;
42 |
43 | public class MainActivity extends Activity {
44 |
45 | private static String BTN_START = "Start Smartlink";
46 | private static String BTN_STOP = "Stop Smartlink";
47 | private EditText txt_ssid;
48 | private EditText txt_password;
49 | private EditText txt_mqtthost;
50 | private Button btn_smartlink;
51 | private WifiManager wm = null;
52 |
53 | @Override
54 | protected void onCreate(Bundle savedInstanceState) {
55 | super.onCreate(savedInstanceState);
56 | setContentView(R.layout.activity_main);
57 | wm = (WifiManager) getSystemService(WIFI_SERVICE);
58 | new UdpThread().start();
59 |
60 | txt_ssid = (EditText) findViewById(R.id.txt_ssid);
61 | txt_password = (EditText) findViewById(R.id.txt_password);
62 | txt_mqtthost = (EditText) findViewById(R.id.txt_mqtthost);
63 |
64 | btn_smartlink = (Button) findViewById(R.id.btn_smartlink);
65 | btn_smartlink.setText(BTN_START);
66 |
67 | txt_ssid.setText(getSSid());
68 |
69 | btn_smartlink.setOnClickListener(new OnClickListener() {
70 | @Override
71 | public void onClick(View v) {
72 | if (btn_smartlink.getText().toString().equals(BTN_START)) {
73 | if (txt_ssid.getText().toString().equals("")) {
74 | new AlertDialog.Builder(MainActivity.this)
75 | .setTitle("Error")
76 | .setMessage("SSID field cannot be empty.")
77 | .show();
78 | return;
79 | }
80 |
81 | UdpThread.send(txt_ssid.getText().toString(), txt_password.getText().toString(), txt_mqtthost.getText().toString());
82 |
83 | btn_smartlink.setText(BTN_STOP);
84 | } else {
85 | btn_smartlink.setText(BTN_START);
86 | }
87 | }
88 | });
89 | }
90 |
91 | private String getSSid() {
92 | if (wm != null) {
93 | WifiInfo wi = wm.getConnectionInfo();
94 | if (wi != null) {
95 | String s = wi.getSSID();
96 | Log.d("SmartlinkActivity", wi.getBSSID() + s.substring(1, s.length() - 1));
97 | if (s.length() > 2 && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"') {
98 | return s.substring(1, s.length() - 1);
99 | }
100 | }
101 | }
102 |
103 | return "";
104 | }
105 |
106 | @Override
107 | public boolean onCreateOptionsMenu(Menu menu) {
108 | getMenuInflater().inflate(R.menu.main, menu);
109 | return true;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/app.iml:
--------------------------------------------------------------------------------
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 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/smartconfig/UdpThread.java:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2015
5 | Stijn van Drunen (www.stijnvandrunen.nl),
6 | younger (https://github.com/youngBuger/esp8266-smartconfig)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 | */
26 |
27 | package com.example.smartconfig;
28 |
29 | import android.os.Bundle;
30 | import android.os.Handler;
31 | import android.os.Looper;
32 | import android.os.Message;
33 | import android.util.Log;
34 |
35 | import java.io.IOException;
36 | import java.net.DatagramPacket;
37 | import java.net.DatagramSocket;
38 | import java.net.InetAddress;
39 | import java.net.UnknownHostException;
40 |
41 |
42 | public class UdpThread extends Thread {
43 |
44 | public final static String TAG = "UdpThread";
45 | static Handler mUdpHandler;
46 | static DatagramSocket udpSocket = null;
47 | static DatagramPacket udpsendPacket = null;
48 |
49 | public static void send(String ssid, String pwd, String mqttHost) {
50 | Bundle bundle = new Bundle();
51 |
52 | bundle.putString("ssid", ssid);
53 | bundle.putString("pwd", pwd);
54 | bundle.putString("mqtthost", mqttHost);
55 |
56 | Message message = new Message();
57 | message.setData(bundle);
58 |
59 | mUdpHandler.sendMessage(message);
60 | }
61 |
62 | @Override
63 | public void run() {
64 | connect();
65 |
66 | Looper.prepare();
67 |
68 | mUdpHandler = new Handler() {
69 | @Override
70 | public void handleMessage(Message msg) {
71 | Bundle data = msg.getData();
72 | send(data);
73 | }
74 | };
75 |
76 | Looper.loop();
77 | }
78 |
79 | private void connect() {
80 | try {
81 | udpSocket = new DatagramSocket(4560);
82 | } catch (Exception e) {
83 | // TODO: Exception should be handled
84 | }
85 | }
86 |
87 | private void send(Bundle bundle) {
88 | try {
89 | String ssid = bundle.getString("ssid");
90 | String pwd = bundle.getString("pwd");
91 | String mqtthost = bundle.getString("mqtthost");
92 |
93 | byte[] encodedBytes = getBytesForSmartConfig(ssid, pwd, mqtthost);
94 | encodedBytes = MakeCRC8(encodedBytes);
95 | byte[] encBuf = SmartLinkEncode(encodedBytes);
96 | byte[] dummybuf = new byte[18];
97 | int delayms = 5;
98 | long beginTime = System.currentTimeMillis();
99 |
100 | udpsendPacket = new DatagramPacket(dummybuf, dummybuf.length);
101 | udpsendPacket.setData(dummybuf);
102 | udpsendPacket.setPort(80);
103 | udpsendPacket.setAddress(InetAddress.getByName("255.255.255.255"));
104 |
105 | while (true) {
106 | delayms++;
107 | if (delayms > 27)
108 | delayms = 20;
109 | for (byte anEncBuf : encBuf) {
110 | udpsendPacket.setLength(anEncBuf);
111 | udpSocket.send(udpsendPacket);
112 | Thread.sleep(delayms);
113 | }
114 | Thread.sleep(200);
115 | if ((System.currentTimeMillis() - beginTime) / 1000 >= 25)
116 | break;
117 | }
118 | } catch (InterruptedException e) {
119 | // TODO Auto-generated catch block
120 | e.printStackTrace();
121 | } catch (UnknownHostException e) {
122 | // TODO Auto-generated catch block
123 | e.printStackTrace();
124 | } catch (IOException e) {
125 | // TODO Auto-generated catch block
126 | e.printStackTrace();
127 | }
128 |
129 | }
130 |
131 | private byte[] SmartLinkEncode(byte[] src) {
132 | byte[] rtlval;
133 | int curidx = 0;
134 | rtlval = new byte[src.length * 10];
135 | byte tmp;
136 | for (int i = 0; i < src.length; i++) {
137 | rtlval[curidx++] = 0;
138 | rtlval[curidx++] = 0;
139 | tmp = (byte) (i & 0xF);
140 | rtlval[curidx++] = (byte) (tmp + 1);//pos_L
141 | rtlval[curidx++] = (byte) ((15 - tmp) + 1);//~pos_L
142 | tmp = (byte) ((i & 0xF0) >> 4);
143 | rtlval[curidx++] = (byte) (tmp + 1);//pos_H
144 | rtlval[curidx++] = (byte) ((15 - tmp) + 1);//~pos_H
145 | tmp = (byte) (src[i] & 0xF);
146 | rtlval[curidx++] = (byte) (tmp + 1);//val_L
147 | rtlval[curidx++] = (byte) ((15 - tmp) + 1);//~val_L
148 | tmp = (byte) ((src[i] & 0xF0) >> 4);
149 | rtlval[curidx++] = (byte) (tmp + 1);//val_H
150 | rtlval[curidx++] = (byte) ((15 - tmp) + 1);//~val_H
151 | }
152 | return rtlval;
153 | }
154 |
155 | byte[] getBytesForSmartConfig(String... values) {
156 | StringBuilder combinedStrings = new StringBuilder();
157 | for(String value : values) {
158 | combinedStrings.append(value);
159 | combinedStrings.append('\n');
160 | }
161 | return combinedStrings.toString().getBytes();
162 | }
163 |
164 | byte[] MakeCRC8(byte[] src) {
165 | byte crc = calcrc_bytes(src, src.length);
166 | byte[] rtlval = new byte[src.length + 1];
167 | System.arraycopy(src, 0, rtlval, 0, src.length);
168 | rtlval[src.length] = crc;
169 | return rtlval;
170 | }
171 |
172 | byte calcrc_bytes(byte[] p, int len) {
173 | byte crc = 0;
174 | int i = 0;
175 | while (i < len) {
176 | crc = (byte) calcrc_1byte(crc ^ p[i]);
177 | int j = crc & 0xff;
178 | Log.e(TAG, "crc=" + j);
179 | i++;
180 | }
181 | return crc;
182 | }
183 |
184 | int calcrc_1byte(int abyte) {
185 | int i, crc_1byte;
186 | crc_1byte = 0;
187 | for (i = 0; i < 8; i++) {
188 | if (((crc_1byte ^ abyte) & 0x01) > 0) {
189 | crc_1byte ^= 0x18;
190 | crc_1byte >>= 1;
191 | crc_1byte |= 0x80;
192 | } else {
193 | crc_1byte >>= 1;
194 | }
195 | abyte >>= 1;
196 | }
197 | return crc_1byte;
198 | }
199 | }
--------------------------------------------------------------------------------