Noduino OpenOnoff
(→概述) |
(→Debug) |
||
(未显示2个用户的70个中间版本) | |||
第1行: | 第1行: | ||
− | == | + | == Overview == |
[[文件:Open-onoff-3.jpg | 600px]] | [[文件:Open-onoff-3.jpg | 600px]] | ||
+ | [[文件:Open-onoff-2.jpg | 600px]] | ||
+ | |||
+ | * AC 85V - 250V General Power Switch | ||
+ | * ESP8285 inside | ||
+ | * 250V 10A relay | ||
+ | * Mainboard size 53mm x 28mm x 17.8mm(H) | ||
+ | * Shell size 63mm x 33mm x 21mm(H) | ||
+ | |||
+ | |||
+ | [[文件:Noduino-works-with-logo.png | 600px]] | ||
第8行: | 第18行: | ||
== Quick Start == | == Quick Start == | ||
+ | |||
+ | [[文件:Open-onoff-4-en.jpg | 600px]] | ||
+ | |||
+ | |||
+ | [[文件:Maike-wifi-ctrl-2233-all-en.jpg]] | ||
+ | |||
+ | |||
+ | We need the WeChat to setup the OpenOnoff :) | ||
+ | |||
+ | |||
+ | * Power off, put the controller join circuit. | ||
+ | |||
+ | * Link OUTPUT port to the lamp or other electrical appliances under 1KW. | ||
+ | |||
+ | * Check the connection since it's 220V/110V. It would be best to reinforce the connection points with home insulation tape. | ||
+ | |||
+ | * Link INPUT port to the home electric supply. (Be Careful, suggest to off the home main breaker) | ||
+ | |||
+ | * Power on, controller will be waiting for network connection with indicator light flash slowly. (If there is no flash or flash quickly, please press the button for 10sec) | ||
+ | |||
+ | * Mobile connect to WiFi, scan the QR code in WeChat to connect network. | ||
+ | |||
+ | * Enter WiFi password, waiting for network connection. (P.S. only 2.4G WiFi is applicable, 5G WiFi and Enterprise - level security certifications are not supportable.) | ||
+ | |||
+ | * Finish WiFi configuration, WeChat will be in LAN devices matching mode with devices list visible. | ||
+ | |||
+ | * Click the first device then press "Link Device" button to bind the device. (P.S. if the device has been binding, then the button at bottom is "Enter Official Account" | ||
+ | |||
+ | * Finish above steps, please press "Enter Official Account" button then click "My Device" button to find your binding devices list. Click the device to enter control page. | ||
+ | |||
+ | |||
+ | If more people need to control the device, please connect to the same router and scan the same QR code while the device is power on. Click "Device connected and skip" -> "Link Device"->"Enter Official Account" to control smart devices | ||
+ | |||
+ | |||
+ | ;;Note: | ||
+ | |||
+ | * Press the button momentarily, manual switch controller | ||
+ | |||
+ | * Press the button 8sec, restore the factory settings. | ||
<br><br> | <br><br> | ||
− | == | + | == Open API == |
+ | |||
+ | Afer you guys 'Link Device' in WeChat, Enter Official Account: | ||
+ | |||
+ | |||
+ | * click "Devices" to list your binding devices | ||
+ | * select your OpenPlug in the list, enter control page, click upright corner, then Copy URL | ||
+ | * paste the URL into web browser (Chrome or Safari) to access the control page in browser | ||
+ | * check the source code of the page to get the following variables: | ||
+ | |||
+ | |||
+ | <source lang=php> | ||
+ | var devid = YOUR_DEVICE_ID; | ||
+ | var mqtt_uname = xxxxxxxx; | ||
+ | </source> | ||
<br><br> | <br><br> | ||
− | == | + | === Go === |
− | + | ==== Prepare ==== | |
− | + | Prepare the Go lang: | |
<source lang=bash> | <source lang=bash> | ||
− | $ | + | $ sudo apt-get install golang-go |
+ | $ sudo apt-get install golang-eclipse-paho-dev | ||
+ | $ export GOPATH=/usr/share/gocode | ||
</source> | </source> | ||
+ | Refer to: | ||
− | + | * https://golang.org | |
+ | * http://www.eclipse.org/paho/clients/golang/ | ||
+ | |||
+ | <br> | ||
+ | |||
+ | ==== Turn On/Off ==== | ||
+ | |||
+ | <source lang=cpp> | ||
+ | package main | ||
+ | |||
+ | import ( | ||
+ | "fmt" | ||
+ | "os" | ||
+ | "strings" | ||
+ | "net/http" | ||
+ | "encoding/json" | ||
+ | MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git" | ||
+ | ) | ||
+ | |||
+ | //define a function for the default message handler | ||
+ | var f MQTT.MessageHandler = func(client *MQTT.Client, msg MQTT.Message) { | ||
+ | fmt.Printf("TOPIC: %s\n", msg.Topic()) | ||
+ | fmt.Printf("MSG: %s\n", msg.Payload()) | ||
+ | } | ||
+ | |||
+ | var uid string = "YOUR_mqtt_uname" | ||
+ | |||
+ | func main() { | ||
+ | if len(os.Args[1:]) >= 2 { | ||
+ | |||
+ | devid := os.Args[1] | ||
+ | cmd := os.Args[2] | ||
+ | msg := "" | ||
+ | |||
+ | if cmd == "on" { | ||
+ | msg = "on" | ||
+ | } else if cmd == "off" { | ||
+ | msg = "off" | ||
+ | } else if cmd == "ota" { | ||
+ | msg = "ota" | ||
+ | } | ||
+ | |||
+ | pass := get_token(uid) | ||
+ | send_msg(devid, msg, pass) | ||
+ | |||
+ | } else { | ||
+ | help_msg() | ||
+ | } | ||
+ | } | ||
+ | |||
+ | func help_msg() { | ||
+ | fmt.Println("Supported cmd:") | ||
+ | fmt.Println("\topenonoff dev_id on") | ||
+ | fmt.Println("\topenonoff dev_id off") | ||
+ | fmt.Println("\topenonoff dev_id ota") | ||
+ | } | ||
+ | |||
+ | func send_msg(devid string, msg string, pass string) { | ||
+ | |||
+ | opts := MQTT.NewClientOptions().AddBroker("tcp://mqtt.noduino.org:1883") | ||
+ | opts.SetClientID("cid_" + devid) | ||
+ | opts.SetUsername(devid) | ||
+ | opts.SetPassword(pass) | ||
+ | opts.SetDefaultPublishHandler(f) | ||
+ | |||
+ | c := MQTT.NewClient(opts) | ||
+ | if token := c.Connect(); token.Wait() && token.Error() != nil { | ||
+ | panic(token.Error()) | ||
+ | } | ||
+ | |||
+ | mqtt_tx_topic := "app2dev/" + devid | ||
+ | |||
+ | token := c.Publish(mqtt_tx_topic, 0, false, msg) | ||
+ | token.Wait() | ||
+ | } | ||
+ | |||
+ | func get_token(user_id string) (string) { | ||
+ | url := "http://api.noduino.org/user/token" | ||
+ | |||
+ | type Body struct { | ||
+ | UID string `json:"user_id"` | ||
+ | } | ||
+ | |||
+ | var body = Body { | ||
+ | UID: user_id, | ||
+ | } | ||
+ | |||
+ | data, err := json.Marshal(body) | ||
+ | //fmt.Println(string(data)) | ||
+ | |||
+ | if err == nil { | ||
+ | resp, err := http.Post(url, "application/json", strings.NewReader(string(data))) | ||
+ | if err != nil { | ||
+ | fmt.Println(err) | ||
+ | } | ||
+ | defer resp.Body.Close() | ||
+ | |||
+ | dec := json.NewDecoder(resp.Body) | ||
+ | var v map[string]interface{} | ||
+ | if err := dec.Decode(&v); err != nil { | ||
+ | fmt.Printf("error: %v\n", err) | ||
+ | } else { | ||
+ | if val, ok := v["user_token"].(string); ok { | ||
+ | return val | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | return "" | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang=bash> | ||
+ | $ go build openonoff.go | ||
+ | $ ./openonoff MKD12343405300 on | ||
+ | $ ./openonoff MKD12343405300 off | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | ==== OTA ==== | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ ./openonoff MKD12343405300 ota | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | === node.js === | ||
+ | |||
+ | ==== Prepare ==== | ||
+ | |||
+ | Download the node-v6.9.1-xxx.tgz from http://nodejs.org | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ tar xf node-v6.9.1-*.tar.xz | ||
+ | $ sudo cp -a node-v6.9.1*/* /usr/local/ | ||
+ | $ sudo npm install -g MQTTClient | ||
+ | $ sudo npm install -g request | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | ==== Turn off ==== | ||
+ | |||
+ | Turn off the plug throught node.js: | ||
+ | |||
+ | * replace the mqtt_uname in line 6 | ||
+ | * replace the devid in line 7 | ||
+ | |||
+ | <source lang=javascript> | ||
+ | $ cat switch.js | ||
+ | #! /usr/bin/env node | ||
+ | |||
+ | // replace it to yours | ||
+ | //////////////////////////////////////////////// | ||
+ | var mqtt_uname = "o7okr76757879RfhBs_AA339"; <---- YOUR_mqtt_uname | ||
+ | var devid = "MJD123456789012"; <---- YOUR_devid | ||
+ | //////////////////////////////////////////////// | ||
+ | |||
+ | var opt = { | ||
+ | username: mqtt_uname, | ||
+ | password: "" | ||
+ | }; | ||
+ | |||
+ | var mqtt_tx_topic = 'app2dev/' + devid | ||
+ | |||
+ | var args = process.argv.slice(2); | ||
+ | var set_state = args[0]; | ||
+ | |||
+ | if (set_state != 'on' && set_state != 'off') { | ||
+ | console.log("Supported cmd:"); | ||
+ | console.log("\tswitch.js on"); | ||
+ | console.log("\tswitch.js off"); | ||
+ | process.exit(1); | ||
+ | } | ||
+ | |||
+ | console.log("st = " + set_state); | ||
+ | |||
+ | var http_req = require('/usr/local/lib/node_modules/request'); | ||
+ | http_req.post( | ||
+ | 'http://api.noduino.org/user/token', | ||
+ | { json: {user_id: opt.username} }, | ||
+ | function (error, response, body) { | ||
+ | if (!error && response.statusCode == 200) { | ||
+ | console.log(body); | ||
+ | |||
+ | opt.password = body.user_token; | ||
+ | //console.log(opt) | ||
+ | |||
+ | var MQTTClient = require('/usr/local/lib/node_modules/MQTTClient').Client; | ||
+ | var client = new MQTTClient('mqtt.noduino.org', 1883, opt); | ||
+ | client.connect(function () { | ||
+ | console.log("connect ok!"); | ||
+ | |||
+ | var pubopt = { | ||
+ | qos_level: 2 | ||
+ | } | ||
+ | |||
+ | client.publish(mqtt_tx_topic, set_state, pubopt, function (message_id) { | ||
+ | console.log("public ok! message_id = " + message_id); | ||
+ | process.exit(0); | ||
+ | }); | ||
+ | }); | ||
+ | } else { | ||
+ | console.log("Request the user token failed"); | ||
+ | process.exit(1); | ||
+ | } | ||
+ | } | ||
+ | ); | ||
+ | |||
+ | $ ./switch.js off | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | ==== Turn On ==== | ||
+ | |||
+ | Turn on the plug: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ ./switch.js on | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | ==== Debug ==== | ||
+ | |||
+ | <font color=red><b>If you get the following error:</b></font> | ||
+ | |||
+ | <source lang=bash> | ||
+ | /usr/local/lib/node_modules/MQTTClient/client.js:56 | ||
+ | throw Error('user names are kept to 12 characters or fewer'); | ||
+ | ^ | ||
+ | |||
+ | Error: user names are kept to 12 characters or fewer | ||
+ | </source> | ||
+ | |||
+ | Please patch the /usr/local/lib/node_modules/MQTTClient/client.js to remove the line of checking the length of username and password: | ||
+ | |||
+ | <source lang=bash> | ||
+ | --- a/client.js | ||
+ | +++ b/client.js | ||
+ | @@ -52,10 +52,10 @@ var Client = exports.Client = function (host, port, options) { | ||
+ | options.alive_timer = 30; | ||
+ | options.ping_timer = parseInt(options.alive_timer * 0.6 * 1000); | ||
+ | // 用户名和密码 | ||
+ | - if (typeof options.username == 'string' && options.username.length > 12) | ||
+ | - throw Error('user names are kept to 12 characters or fewer'); | ||
+ | - if (typeof options.password == 'string' && options.password.length > 12) | ||
+ | - throw Error('passwords are kept to 12 characters or fewer'); | ||
+ | + //if (typeof options.username == 'string' && options.username.length > 12) | ||
+ | + // throw Error('user names are kept to 12 characters or fewer'); | ||
+ | + //if (typeof options.password == 'string' && options.password.length > 12) | ||
+ | + // throw Error('passwords are kept to 12 characters or fewer'); | ||
+ | // Will flag | ||
+ | if (options.will_flag && (typeof options.will_topic != 'string' || typeof options.will_message != 'string')) | ||
+ | throw Error('missing will_topic or will_message when will_flag is set'); | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | === python === | ||
+ | |||
+ | ==== Prepare ==== | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ python3 --version | ||
+ | Python 3.5.3rc1 | ||
+ | |||
+ | $ pip3 install paho-mqtt | ||
+ | Collecting paho-mqtt | ||
+ | Downloading paho-mqtt-1.2.tar.gz (49kB) | ||
+ | 100% |████████████████████████████████| 51kB 308kB/s | ||
+ | Building wheels for collected packages: paho-mqtt | ||
+ | Running setup.py bdist_wheel for paho-mqtt ... done | ||
+ | Stored in directory: /home/comcat/.cache/pip/wheels/fa/db/fb/b495e37057e2f40534726b3c00ab26a58fc80fb8d17223df07 | ||
+ | Successfully built paho-mqtt | ||
+ | Installing collected packages: paho-mqtt | ||
+ | Successfully installed paho-mqtt-1.2 | ||
+ | </source> | ||
+ | |||
+ | |||
+ | More infor: https://pypi.python.org/pypi/paho-mqtt | ||
+ | |||
+ | <br> | ||
+ | |||
+ | ==== Turn off ==== | ||
+ | |||
+ | * replace the mqtt_uname in line 10 | ||
+ | * replace the devid in line 11 | ||
+ | |||
+ | <source lang=python> | ||
+ | $ cat switch.py | ||
+ | #!/usr/bin/python3 | ||
+ | |||
+ | import json, requests | ||
+ | import paho.mqtt.client as mqtt | ||
+ | import sys | ||
+ | |||
+ | # replace it to your id | ||
+ | ########################################### | ||
+ | mqtt_uname = 'o7okr76757879RfhBs_XM339' <---- YOUR_mqtt_uname | ||
+ | devid = 'MJD123456789012' <---- YOUR_devid | ||
+ | ########################################### | ||
+ | |||
+ | def help_msg(): | ||
+ | print("Supported cmd:") | ||
+ | print("\tswitch.py on") | ||
+ | print("\tswitch.py off") | ||
+ | |||
+ | if len(sys.argv) >= 2: | ||
+ | set_state = sys.argv[1] | ||
+ | else: | ||
+ | help_msg() | ||
+ | sys.exit(-2) | ||
+ | |||
+ | if set_state != 'on' and set_state != 'off': | ||
+ | help_msg() | ||
+ | sys.exit(-2) | ||
+ | |||
+ | url = 'http://api.noduino.org/user/token' | ||
+ | |||
+ | dat = dict ( | ||
+ | user_id = mqtt_uname, | ||
+ | ) | ||
+ | |||
+ | try: | ||
+ | resp = requests.post(url = url, json = dat) | ||
+ | except Exception as e: | ||
+ | print(e) | ||
+ | sys.exit(-1) | ||
+ | |||
+ | p = resp.json() | ||
+ | mqtt_pass = p['user_token'] | ||
+ | |||
+ | mqtt_rx_topic = 'dev2app/' + devid | ||
+ | mqtt_tx_topic = 'app2dev/' + devid | ||
+ | |||
+ | mqtt_host = 'mqtt.noduino.org' | ||
+ | mqtt_port = 1883 | ||
+ | mqtt_msg = set_state | ||
+ | |||
+ | def on_connect(client, u_dat, rc): | ||
+ | if rc == 0: | ||
+ | print("Connected successfully") | ||
+ | else: | ||
+ | print("Connection failed. rc = "+str(rc)) | ||
+ | |||
+ | def on_publish(client, u_dat, rc): | ||
+ | print("Message "+str(rc)+" published.") | ||
+ | |||
+ | def on_subscribe(client, u_dat, mid, qos): | ||
+ | print("Subscribe with "+str(mid)+" received") | ||
+ | |||
+ | def on_message(client, udat, msg): | ||
+ | print("Message received on topic "+msg.topic+" and payload "+str(msg.payload)) | ||
+ | |||
+ | mqttc = mqtt.Client() | ||
+ | |||
+ | mqttc.on_connect = on_connect | ||
+ | mqttc.on_publish = on_publish | ||
+ | mqttc.on_subscribe = on_subscribe | ||
+ | mqttc.on_message = on_message | ||
+ | |||
+ | mqttc.username_pw_set(mqtt_uname, mqtt_pass) | ||
+ | mqttc.connect(mqtt_host, mqtt_port) | ||
+ | |||
+ | mqttc.publish(mqtt_tx_topic, mqtt_msg) | ||
+ | |||
+ | #mqttc.subscribe(mqtt_rx_topic) | ||
+ | #mqttc.loop_forever() | ||
+ | </source> | ||
+ | |||
+ | |||
+ | <source lang=bash> | ||
+ | $ ./switch.py off | ||
+ | </source> | ||
+ | |||
+ | <br> | ||
+ | |||
+ | ==== Turn On ==== | ||
+ | |||
+ | Turn on the plug: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ ./switch.py on | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | === HTML5 === | ||
+ | |||
+ | The device control page in WeChat is a H5 page. Using a MQTT client implement in javascript , using the mqttws31.js library: | ||
+ | |||
+ | <source lang=javascript> | ||
+ | var client_id = parseInt(Math.random() * 10000, 10) + '_' + mqtt_uname; | ||
+ | var client = new Paho.MQTT.Client(mqtt_server, mqtt_port, "/mqtt", client_id); | ||
+ | var state = 0; | ||
+ | function failConnect(e) { | ||
+ | console.log("connect failed"); | ||
+ | console.log(e); | ||
+ | console.log("reconnecting ..."); | ||
+ | client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); | ||
+ | } | ||
+ | function onConnect() { | ||
+ | console.log("onConnect OK!"); | ||
+ | subscribe('dev2app/' + devid); | ||
+ | } | ||
+ | function subscribe(topic) { | ||
+ | client.subscribe(topic); | ||
+ | } | ||
+ | function onMessageArrived (message) { | ||
+ | // MQTT message from device example: {"m":"status","d":"on","t":"2015-12-30T00:00:00+08:00"} | ||
+ | console.log("Arrived Message: [", message.payloadString, "]"); | ||
+ | try { | ||
+ | job = JSON.parse(message.payloadString); | ||
+ | state = job.d; | ||
+ | } catch(e) { | ||
+ | console.log("JSON object error!"); | ||
+ | alert("JSON error, RX data is: " + message.payloadString); | ||
+ | return; | ||
+ | } | ||
+ | if(state == 'on') { | ||
+ | $('#switch').removeClass('btn_off'); | ||
+ | $('#switch').addClass('btn_on'); | ||
+ | } else if (state == 'off') { | ||
+ | $('#switch').removeClass('btn_on'); | ||
+ | $('#switch').addClass('btn_off'); | ||
+ | } | ||
+ | } | ||
+ | function onDisConnect() { | ||
+ | console.log("reconnecting ..."); | ||
+ | client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); | ||
+ | } | ||
+ | function publish(topic, msg){ | ||
+ | message = new Paho.MQTT.Message(msg); | ||
+ | message.destinationName = topic; | ||
+ | client.send(message); | ||
+ | console.log("publish message ok!"); | ||
+ | } | ||
+ | function init() { | ||
+ | client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); | ||
+ | client.onMessageArrived = onMessageArrived; | ||
+ | client.onConnectionLost = onDisConnect; | ||
+ | } | ||
+ | function toggle() | ||
+ | { | ||
+ | //console.log("toggle_devid = " + devid); | ||
+ | var p_topic = "app2dev/" + devid; | ||
+ | if($('#switch').hasClass('btn_off')) { | ||
+ | //console.log("toggle off, topic = " + p_topic); | ||
+ | publish(p_topic, "on"); | ||
+ | } else if ($('#switch').hasClass('btn_on')) { | ||
+ | //console.log("toggle off, topic = " + p_topic); | ||
+ | publish(p_topic, "off"); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == Open API (HTTP in LAN) == | ||
+ | |||
+ | <b style="color:#f00">Note: the device security policy using the WiFi router's password, that is: the users who are authorized to connect to the WiFi router, is a trusted user</b> | ||
+ | |||
+ | Device start a HTTP service by default. You can send the following HTTP request to turn on or turn off the device. This way independent of MQTT cloud service can be used in local area network when you don't want to make device access Internet. | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Get the device IP === | ||
+ | |||
+ | You can use the Fing app in iOS to scan the LAN network. | ||
+ | |||
+ | The device named '''Espressif''' is your OpenPlug device: | ||
+ | |||
+ | |||
+ | [[文件:Fing-lan-scan.png | 400px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Turn On via HTTP in LAN === | ||
+ | |||
+ | 192.168.1.75 is the openplug device IP | ||
+ | |||
+ | Turn On: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ cat plug-on.txt | ||
+ | POST /upnp/control/basicevent1 HTTP/1.1 | ||
+ | Host: 192.168.1.69 | ||
+ | Accept: */* | ||
+ | Content-type: text/xml; charset="utf-8" | ||
+ | Content-Length: 83 | ||
+ | |||
+ | <?xml version="1.0" encoding="utf-8"?><s:Body><BinaryState>1</BinaryState></s:Body> | ||
+ | $ cat plug-on.txt | nc 192.168.1.75 80 | ||
+ | HTTP/1.0 200 OK | ||
+ | Server: lwIP/1.4.0 | ||
+ | Content-type: text/plain | ||
+ | Content-Length: 0 | ||
+ | Connection: close | ||
+ | |||
+ | </source> | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Turn Off via HTTP in LAN === | ||
+ | |||
+ | 192.168.1.75 is the openplug device IP | ||
+ | |||
+ | Turn Off: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ cat plug-off.txt | ||
+ | POST /upnp/control/basicevent1 HTTP/1.1 | ||
+ | Accept: */* | ||
+ | Content-type: text/xml; charset="utf-8" | ||
+ | Content-Length: 83 | ||
+ | |||
+ | <?xml version="1.0" encoding="utf-8"?><s:Body><BinaryState>0</BinaryState></s:Body> | ||
+ | $ cat plug-off.txt | nc 192.168.1.75 80 | ||
+ | HTTP/1.0 200 OK | ||
+ | Server: lwIP/1.4.0 | ||
+ | Content-type: text/plain | ||
+ | Content-Length: 0 | ||
+ | Connection: close | ||
+ | |||
+ | </source> | ||
+ | |||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == HomeBridge == | ||
+ | |||
+ | To use the Siri to control the device :) | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == Alexa == | ||
+ | |||
+ | '''Support Amazon Alexa:''' | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Discover === | ||
+ | |||
+ | [[文件:Alexa-noduino-discove.png | 500px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Turn On === | ||
+ | |||
+ | Note that the default voice name of OpenOnoff is 'open switch' | ||
+ | |||
+ | [[文件:Alexa-openplug-turnon.png | 500px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Turn Off === | ||
+ | |||
+ | Note that the default voice name of OpenOnoff is 'open switch' | ||
+ | |||
+ | [[文件:Alexa-openplug-turnoff.png | 500px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === Debug === | ||
+ | |||
+ | UPNP discovery: | ||
+ | |||
+ | <source lang=bash> | ||
+ | comcat@jackslab:/work/alexa/test$ cat dis.txt | ||
+ | M-SEARCH * HTTP/1.1 | ||
+ | HOST: 239.255.255.250:1900 | ||
+ | MAN: "ssdp:discover" | ||
+ | ST: urn:Belkin:device:** | ||
+ | MX: 3 | ||
+ | comcat@jackslab:/work/alexa/test$ socat -T1 STDIO UDP4-DATAGRAM:239.255.255.250:1900 < dis.txt | ||
+ | HTTP/1.1 200 OK | ||
+ | EXT: | ||
+ | CACHE-CONTROL: max-age=86400 | ||
+ | SERVER: Noduino/1.0 UPNP/1.1 OpenPlug/2.0 | ||
+ | USN: uuid:38323636-4558-4dda-9188-cda0810b2e50 | ||
+ | ST: urn:Belkin:device:** | ||
+ | LOCATION: http://192.168.1.195:80/setup.xml | ||
+ | </source> | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == Hacking == | ||
+ | |||
+ | === Prepare firmware === | ||
+ | |||
+ | Get noduino-sdk: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ git clone --recursive git://github.com/noduino/noduino-sdk.git noduino-sdk | ||
+ | </source> | ||
+ | |||
+ | |||
+ | Generate toolchain (you need Python 2.7): | ||
<source lang=bash> | <source lang=bash> | ||
第33行: | 第701行: | ||
</source> | </source> | ||
− | + | Compile the firmware: | |
<source lang=bash> | <source lang=bash> | ||
$ cd ../sketch/open-onoff | $ cd ../sketch/open-onoff | ||
− | $ make | + | $ make |
</source> | </source> | ||
+ | The generated firmware is located in build/ dir named user1.bin annnd user2.bin | ||
+ | |||
+ | |||
+ | Window environment please refer to [[Getting Started with Noduino SDK on Windows]], you can get how to setup the basic developmennt environment | ||
<br><br> | <br><br> | ||
+ | |||
+ | === Upload === | ||
+ | |||
+ | ==== Serial ==== | ||
+ | |||
+ | Same as OpenPlug, you can refer to the OpenPlug example: | ||
+ | |||
+ | [[文件:Openplug-fw-upload.jpg | 800px]] | ||
+ | |||
+ | |||
+ | [[文件:Ft232.jpg | 800px]] | ||
+ | |||
+ | |||
+ | * USB2UART_GND ------> SmartNode_GPIO0 | ||
+ | * USB2UAR_GND -----> SmartNode_GND | ||
+ | * USB2UAR_RXD -----> SmartNode_TX | ||
+ | * USB2UAR_TXD -----> SmartNode_RX | ||
+ | |||
+ | |||
+ | Connect USB2UAR_VCC3.3 -----> SmartNode_VCC at last | ||
+ | |||
+ | ESP8285 will be enter upload mode, we can upload the compiled firmware through serial using following commands in Linux: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ cd /path/to/noduino-sdk/sketch/open-onoff | ||
+ | $ make produce ESPPORT=/dev/ttyUSB0 | ||
+ | </source> | ||
+ | |||
+ | |||
+ | In windows: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ make produce ESPPORT=COM7 | ||
+ | </source> | ||
+ | |||
+ | COM7 is your USB2UART device | ||
+ | |||
+ | |||
+ | In MAC OS, maybe it's: | ||
+ | |||
+ | <source lang=bash> | ||
+ | $ make produce ESPPORT=/dev/cu.SLAB_USBtoUART | ||
+ | </source> | ||
+ | |||
+ | /dev/cu.SLAB_USBtoUART is your USB2UART device | ||
+ | |||
<br><br> | <br><br> | ||
+ | |||
+ | ==== Online ==== | ||
+ | |||
+ | ;; Access: http://dev.noduino.org/openonoff | ||
+ | |||
+ | |||
+ | ;; Login: | ||
+ | |||
+ | * Username: noduino | ||
+ | * password: noduino1234 | ||
+ | |||
+ | |||
+ | ;; Click the "Add files", select the user1.bin and user2.bin located in /path/to/noduino-sdk/sketch/open-onoff/build/ | ||
+ | |||
+ | |||
+ | ;; Then click "Start upload" to upload the user1.bin and user2.bin into the server temporaily | ||
+ | |||
+ | |||
+ | ;; Enter Official Account, then click "Add" menu, enter "Debug" page | ||
+ | |||
+ | [[文件:Maike-upload-online-1.jpg | 450px]] | ||
+ | |||
+ | |||
+ | ;; Select your device and the input "ota" in the data aera then click "send data" | ||
+ | |||
+ | |||
+ | [[文件:Maike-upload-online-2.jpg | 450px]] | ||
+ | |||
+ | |||
+ | Device will download your user1.bin or user2.bin and write it into flash when the device received the "ota" message | ||
+ | |||
+ | You will see the device online message in the Debug page when the uploading is finished | ||
+ | |||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == Hardware == | ||
+ | |||
+ | [[文件:OpenOnoff-V1.0-sch.png | 900px]] | ||
+ | |||
+ | |||
+ | [[文件:OpenOnoff-V1.0-layout.png]] | ||
+ | |||
+ | <br><br><br> | ||
+ | |||
+ | == Reference == | ||
+ | |||
+ | ;;For more information please refer to: | ||
+ | |||
+ | * [[Noduino]] | ||
+ | * Github: https://github.com/icamgo/noduino-sdk | ||
+ | |||
+ | <br><br> | ||
+ | |||
<br><br> | <br><br> | ||
<br><br> | <br><br> |
2018年10月4日 (四) 14:03的最后版本
目录 |
[编辑] 1 Overview
- AC 85V - 250V General Power Switch
- ESP8285 inside
- 250V 10A relay
- Mainboard size 53mm x 28mm x 17.8mm(H)
- Shell size 63mm x 33mm x 21mm(H)
[编辑] 2 Quick Start
We need the WeChat to setup the OpenOnoff :)
- Power off, put the controller join circuit.
- Link OUTPUT port to the lamp or other electrical appliances under 1KW.
- Check the connection since it's 220V/110V. It would be best to reinforce the connection points with home insulation tape.
- Link INPUT port to the home electric supply. (Be Careful, suggest to off the home main breaker)
- Power on, controller will be waiting for network connection with indicator light flash slowly. (If there is no flash or flash quickly, please press the button for 10sec)
- Mobile connect to WiFi, scan the QR code in WeChat to connect network.
- Enter WiFi password, waiting for network connection. (P.S. only 2.4G WiFi is applicable, 5G WiFi and Enterprise - level security certifications are not supportable.)
- Finish WiFi configuration, WeChat will be in LAN devices matching mode with devices list visible.
- Click the first device then press "Link Device" button to bind the device. (P.S. if the device has been binding, then the button at bottom is "Enter Official Account"
- Finish above steps, please press "Enter Official Account" button then click "My Device" button to find your binding devices list. Click the device to enter control page.
If more people need to control the device, please connect to the same router and scan the same QR code while the device is power on. Click "Device connected and skip" -> "Link Device"->"Enter Official Account" to control smart devices
- Note
- Press the button momentarily, manual switch controller
- Press the button 8sec, restore the factory settings.
[编辑] 3 Open API
Afer you guys 'Link Device' in WeChat, Enter Official Account:
- click "Devices" to list your binding devices
- select your OpenPlug in the list, enter control page, click upright corner, then Copy URL
- paste the URL into web browser (Chrome or Safari) to access the control page in browser
- check the source code of the page to get the following variables:
var devid = YOUR_DEVICE_ID; var mqtt_uname = xxxxxxxx;
[编辑] 3.1 Go
[编辑] 3.1.1 Prepare
Prepare the Go lang:
$ sudo apt-get install golang-go $ sudo apt-get install golang-eclipse-paho-dev $ export GOPATH=/usr/share/gocode
Refer to:
[编辑] 3.1.2 Turn On/Off
package main import ( "fmt" "os" "strings" "net/http" "encoding/json" MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git" ) //define a function for the default message handler var f MQTT.MessageHandler = func(client *MQTT.Client, msg MQTT.Message) { fmt.Printf("TOPIC: %s\n", msg.Topic()) fmt.Printf("MSG: %s\n", msg.Payload()) } var uid string = "YOUR_mqtt_uname" func main() { if len(os.Args[1:]) >= 2 { devid := os.Args[1] cmd := os.Args[2] msg := "" if cmd == "on" { msg = "on" } else if cmd == "off" { msg = "off" } else if cmd == "ota" { msg = "ota" } pass := get_token(uid) send_msg(devid, msg, pass) } else { help_msg() } } func help_msg() { fmt.Println("Supported cmd:") fmt.Println("\topenonoff dev_id on") fmt.Println("\topenonoff dev_id off") fmt.Println("\topenonoff dev_id ota") } func send_msg(devid string, msg string, pass string) { opts := MQTT.NewClientOptions().AddBroker("tcp://mqtt.noduino.org:1883") opts.SetClientID("cid_" + devid) opts.SetUsername(devid) opts.SetPassword(pass) opts.SetDefaultPublishHandler(f) c := MQTT.NewClient(opts) if token := c.Connect(); token.Wait() && token.Error() != nil { panic(token.Error()) } mqtt_tx_topic := "app2dev/" + devid token := c.Publish(mqtt_tx_topic, 0, false, msg) token.Wait() } func get_token(user_id string) (string) { url := "http://api.noduino.org/user/token" type Body struct { UID string `json:"user_id"` } var body = Body { UID: user_id, } data, err := json.Marshal(body) //fmt.Println(string(data)) if err == nil { resp, err := http.Post(url, "application/json", strings.NewReader(string(data))) if err != nil { fmt.Println(err) } defer resp.Body.Close() dec := json.NewDecoder(resp.Body) var v map[string]interface{} if err := dec.Decode(&v); err != nil { fmt.Printf("error: %v\n", err) } else { if val, ok := v["user_token"].(string); ok { return val } } } return "" }
$ go build openonoff.go $ ./openonoff MKD12343405300 on $ ./openonoff MKD12343405300 off
[编辑] 3.1.3 OTA
$ ./openonoff MKD12343405300 ota
[编辑] 3.2 node.js
[编辑] 3.2.1 Prepare
Download the node-v6.9.1-xxx.tgz from http://nodejs.org
$ tar xf node-v6.9.1-*.tar.xz $ sudo cp -a node-v6.9.1*/* /usr/local/ $ sudo npm install -g MQTTClient $ sudo npm install -g request
[编辑] 3.2.2 Turn off
Turn off the plug throught node.js:
- replace the mqtt_uname in line 6
- replace the devid in line 7
$ cat switch.js #! /usr/bin/env node // replace it to yours //////////////////////////////////////////////// var mqtt_uname = "o7okr76757879RfhBs_AA339"; <---- YOUR_mqtt_uname var devid = "MJD123456789012"; <---- YOUR_devid //////////////////////////////////////////////// var opt = { username: mqtt_uname, password: "" }; var mqtt_tx_topic = 'app2dev/' + devid var args = process.argv.slice(2); var set_state = args[0]; if (set_state != 'on' && set_state != 'off') { console.log("Supported cmd:"); console.log("\tswitch.js on"); console.log("\tswitch.js off"); process.exit(1); } console.log("st = " + set_state); var http_req = require('/usr/local/lib/node_modules/request'); http_req.post( 'http://api.noduino.org/user/token', { json: {user_id: opt.username} }, function (error, response, body) { if (!error && response.statusCode == 200) { console.log(body); opt.password = body.user_token; //console.log(opt) var MQTTClient = require('/usr/local/lib/node_modules/MQTTClient').Client; var client = new MQTTClient('mqtt.noduino.org', 1883, opt); client.connect(function () { console.log("connect ok!"); var pubopt = { qos_level: 2 } client.publish(mqtt_tx_topic, set_state, pubopt, function (message_id) { console.log("public ok! message_id = " + message_id); process.exit(0); }); }); } else { console.log("Request the user token failed"); process.exit(1); } } ); $ ./switch.js off
[编辑] 3.2.3 Turn On
Turn on the plug:
$ ./switch.js on
[编辑] 3.2.4 Debug
If you get the following error:
/usr/local/lib/node_modules/MQTTClient/client.js:56 throw Error('user names are kept to 12 characters or fewer'); ^ Error: user names are kept to 12 characters or fewer
Please patch the /usr/local/lib/node_modules/MQTTClient/client.js to remove the line of checking the length of username and password:
--- a/client.js +++ b/client.js @@ -52,10 +52,10 @@ var Client = exports.Client = function (host, port, options) { options.alive_timer = 30; options.ping_timer = parseInt(options.alive_timer * 0.6 * 1000); // 用户名和密码 - if (typeof options.username == 'string' && options.username.length > 12) - throw Error('user names are kept to 12 characters or fewer'); - if (typeof options.password == 'string' && options.password.length > 12) - throw Error('passwords are kept to 12 characters or fewer'); + //if (typeof options.username == 'string' && options.username.length > 12) + // throw Error('user names are kept to 12 characters or fewer'); + //if (typeof options.password == 'string' && options.password.length > 12) + // throw Error('passwords are kept to 12 characters or fewer'); // Will flag if (options.will_flag && (typeof options.will_topic != 'string' || typeof options.will_message != 'string')) throw Error('missing will_topic or will_message when will_flag is set');
[编辑] 3.3 python
[编辑] 3.3.1 Prepare
$ python3 --version Python 3.5.3rc1 $ pip3 install paho-mqtt Collecting paho-mqtt Downloading paho-mqtt-1.2.tar.gz (49kB) 100% |████████████████████████████████| 51kB 308kB/s Building wheels for collected packages: paho-mqtt Running setup.py bdist_wheel for paho-mqtt ... done Stored in directory: /home/comcat/.cache/pip/wheels/fa/db/fb/b495e37057e2f40534726b3c00ab26a58fc80fb8d17223df07 Successfully built paho-mqtt Installing collected packages: paho-mqtt Successfully installed paho-mqtt-1.2
More infor: https://pypi.python.org/pypi/paho-mqtt
[编辑] 3.3.2 Turn off
- replace the mqtt_uname in line 10
- replace the devid in line 11
$ cat switch.py #!/usr/bin/python3 import json, requests import paho.mqtt.client as mqtt import sys # replace it to your id ########################################### mqtt_uname = 'o7okr76757879RfhBs_XM339' <---- YOUR_mqtt_uname devid = 'MJD123456789012' <---- YOUR_devid ########################################### def help_msg(): print("Supported cmd:") print("\tswitch.py on") print("\tswitch.py off") if len(sys.argv) >= 2: set_state = sys.argv[1] else: help_msg() sys.exit(-2) if set_state != 'on' and set_state != 'off': help_msg() sys.exit(-2) url = 'http://api.noduino.org/user/token' dat = dict ( user_id = mqtt_uname, ) try: resp = requests.post(url = url, json = dat) except Exception as e: print(e) sys.exit(-1) p = resp.json() mqtt_pass = p['user_token'] mqtt_rx_topic = 'dev2app/' + devid mqtt_tx_topic = 'app2dev/' + devid mqtt_host = 'mqtt.noduino.org' mqtt_port = 1883 mqtt_msg = set_state def on_connect(client, u_dat, rc): if rc == 0: print("Connected successfully") else: print("Connection failed. rc = "+str(rc)) def on_publish(client, u_dat, rc): print("Message "+str(rc)+" published.") def on_subscribe(client, u_dat, mid, qos): print("Subscribe with "+str(mid)+" received") def on_message(client, udat, msg): print("Message received on topic "+msg.topic+" and payload "+str(msg.payload)) mqttc = mqtt.Client() mqttc.on_connect = on_connect mqttc.on_publish = on_publish mqttc.on_subscribe = on_subscribe mqttc.on_message = on_message mqttc.username_pw_set(mqtt_uname, mqtt_pass) mqttc.connect(mqtt_host, mqtt_port) mqttc.publish(mqtt_tx_topic, mqtt_msg) #mqttc.subscribe(mqtt_rx_topic) #mqttc.loop_forever()
$ ./switch.py off
[编辑] 3.3.3 Turn On
Turn on the plug:
$ ./switch.py on
[编辑] 3.4 HTML5
The device control page in WeChat is a H5 page. Using a MQTT client implement in javascript , using the mqttws31.js library:
var client_id = parseInt(Math.random() * 10000, 10) + '_' + mqtt_uname; var client = new Paho.MQTT.Client(mqtt_server, mqtt_port, "/mqtt", client_id); var state = 0; function failConnect(e) { console.log("connect failed"); console.log(e); console.log("reconnecting ..."); client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); } function onConnect() { console.log("onConnect OK!"); subscribe('dev2app/' + devid); } function subscribe(topic) { client.subscribe(topic); } function onMessageArrived (message) { // MQTT message from device example: {"m":"status","d":"on","t":"2015-12-30T00:00:00+08:00"} console.log("Arrived Message: [", message.payloadString, "]"); try { job = JSON.parse(message.payloadString); state = job.d; } catch(e) { console.log("JSON object error!"); alert("JSON error, RX data is: " + message.payloadString); return; } if(state == 'on') { $('#switch').removeClass('btn_off'); $('#switch').addClass('btn_on'); } else if (state == 'off') { $('#switch').removeClass('btn_on'); $('#switch').addClass('btn_off'); } } function onDisConnect() { console.log("reconnecting ..."); client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); } function publish(topic, msg){ message = new Paho.MQTT.Message(msg); message.destinationName = topic; client.send(message); console.log("publish message ok!"); } function init() { client.connect({userName: mqtt_uname, password: mqtt_pass, onSuccess:onConnect, onFailure: failConnect, mqttVersion:3}); client.onMessageArrived = onMessageArrived; client.onConnectionLost = onDisConnect; } function toggle() { //console.log("toggle_devid = " + devid); var p_topic = "app2dev/" + devid; if($('#switch').hasClass('btn_off')) { //console.log("toggle off, topic = " + p_topic); publish(p_topic, "on"); } else if ($('#switch').hasClass('btn_on')) { //console.log("toggle off, topic = " + p_topic); publish(p_topic, "off"); } }
[编辑] 4 Open API (HTTP in LAN)
Note: the device security policy using the WiFi router's password, that is: the users who are authorized to connect to the WiFi router, is a trusted user
Device start a HTTP service by default. You can send the following HTTP request to turn on or turn off the device. This way independent of MQTT cloud service can be used in local area network when you don't want to make device access Internet.
[编辑] 4.1 Get the device IP
You can use the Fing app in iOS to scan the LAN network.
The device named Espressif is your OpenPlug device:
[编辑] 4.2 Turn On via HTTP in LAN
192.168.1.75 is the openplug device IP
Turn On:
$ cat plug-on.txt POST /upnp/control/basicevent1 HTTP/1.1 Host: 192.168.1.69 Accept: */* Content-type: text/xml; charset="utf-8" Content-Length: 83 <?xml version="1.0" encoding="utf-8"?><s:Body><BinaryState>1</BinaryState></s:Body> $ cat plug-on.txt | nc 192.168.1.75 80 HTTP/1.0 200 OK Server: lwIP/1.4.0 Content-type: text/plain Content-Length: 0 Connection: close
[编辑] 4.3 Turn Off via HTTP in LAN
192.168.1.75 is the openplug device IP
Turn Off:
$ cat plug-off.txt POST /upnp/control/basicevent1 HTTP/1.1 Accept: */* Content-type: text/xml; charset="utf-8" Content-Length: 83 <?xml version="1.0" encoding="utf-8"?><s:Body><BinaryState>0</BinaryState></s:Body> $ cat plug-off.txt | nc 192.168.1.75 80 HTTP/1.0 200 OK Server: lwIP/1.4.0 Content-type: text/plain Content-Length: 0 Connection: close
[编辑] 5 HomeBridge
To use the Siri to control the device :)
[编辑] 6 Alexa
Support Amazon Alexa:
[编辑] 6.1 Discover
[编辑] 6.2 Turn On
Note that the default voice name of OpenOnoff is 'open switch'
[编辑] 6.3 Turn Off
Note that the default voice name of OpenOnoff is 'open switch'
[编辑] 6.4 Debug
UPNP discovery:
comcat@jackslab:/work/alexa/test$ cat dis.txt M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" ST: urn:Belkin:device:** MX: 3 comcat@jackslab:/work/alexa/test$ socat -T1 STDIO UDP4-DATAGRAM:239.255.255.250:1900 < dis.txt HTTP/1.1 200 OK EXT: CACHE-CONTROL: max-age=86400 SERVER: Noduino/1.0 UPNP/1.1 OpenPlug/2.0 USN: uuid:38323636-4558-4dda-9188-cda0810b2e50 ST: urn:Belkin:device:** LOCATION: http://192.168.1.195:80/setup.xml
[编辑] 7 Hacking
[编辑] 7.1 Prepare firmware
Get noduino-sdk:
$ git clone --recursive git://github.com/noduino/noduino-sdk.git noduino-sdk
Generate toolchain (you need Python 2.7):
$ cd noduino-sdk/toolchain $ ./gen.py
Compile the firmware:
$ cd ../sketch/open-onoff $ make
The generated firmware is located in build/ dir named user1.bin annnd user2.bin
Window environment please refer to Getting Started with Noduino SDK on Windows, you can get how to setup the basic developmennt environment
[编辑] 7.2 Upload
[编辑] 7.2.1 Serial
Same as OpenPlug, you can refer to the OpenPlug example:
- USB2UART_GND ------> SmartNode_GPIO0
- USB2UAR_GND -----> SmartNode_GND
- USB2UAR_RXD -----> SmartNode_TX
- USB2UAR_TXD -----> SmartNode_RX
Connect USB2UAR_VCC3.3 -----> SmartNode_VCC at last
ESP8285 will be enter upload mode, we can upload the compiled firmware through serial using following commands in Linux:
$ cd /path/to/noduino-sdk/sketch/open-onoff $ make produce ESPPORT=/dev/ttyUSB0
In windows:
$ make produce ESPPORT=COM7
COM7 is your USB2UART device
In MAC OS, maybe it's:
$ make produce ESPPORT=/dev/cu.SLAB_USBtoUART
/dev/cu.SLAB_USBtoUART is your USB2UART device
[编辑] 7.2.2 Online
- Login
- Username: noduino
- password: noduino1234
- Click the "Add files", select the user1.bin and user2.bin located in /path/to/noduino-sdk/sketch/open-onoff/build/
- Then click "Start upload" to upload the user1.bin and user2.bin into the server temporaily
- Enter Official Account, then click "Add" menu, enter "Debug" page
- Select your device and the input "ota" in the data aera then click "send data"
Device will download your user1.bin or user2.bin and write it into flash when the device received the "ota" message
You will see the device online message in the Debug page when the uploading is finished
[编辑] 8 Hardware
[编辑] 9 Reference
- For more information please refer to