ULB Guide - Seeed-Studio/Wio_Link GitHub Wiki
This guide will show you how to use the ULB ( User Logic Block) feature of Wio Link. The ULB is a piece of code that can be uploaded to the OTA server of Wio and be compiled at the OTA server, then be OTA to the Wio board.
Configure the board
First of all, configure the board as do you before, via the mobile app. Here's an example, I connected two Groves: Grove - Light Sensor and Grove -Relay. Click the "Update Firmware" button to finish the firmware OTA.
Connect the real components to the Wio board, according to the configuration in your app.
Get the access_token
We can easily get the access_token in the mobile app. I used the "Share" button to share the whole URL to my laptop. On the laptop, it will be easier to copy paste things.
After opening the API page, we can get the following strings which are needed in the next steps:
- server domain: https://cn.wio.seeed.io (this can be different depending on which server you chose)
- access_token: 9bfc9a8c9c2c975bb4b770ca0fd088b1
Program the ULB
To program the ULB we must start with the sketch generated by the server, because the server translated the Grove modules configuration map into proper codes ( include headers, module Class initialization, etc.). To download the sketch from the server, we need to call some APIs. We built a simple helper script to simplify the API call.
Helper script
To use this script we need Python environment, and we need to install the dependences:
$ pip install requests
# make a dir for the ULB project
$ mkdir ulb_demo
$ cd ulb_demo
$ wget https://gist.github.com/KillingJacky/8cd5974c22b39bb5822fbc3f8398a404/raw/d0fcfacf04f33c84ffde03a3456d66cce47a2436/ulb_helper.py
$ chmod a+x ulb_helper.py
$ ./ulb_helper.py --help
Download ULB
Download the ULB sketch into the current directory, use the previously saved server domain
and access_token
.
$ ./ulb_helper.py get https://cn.wio.seeed.io 9bfc9a8c9c2c975bb4b770ca0fd088b1
=> The Response
{u'./Main.h': u'#ifndef __MAIN_H__\r\n#define __MAIN_H__\r\n#include "suli2.h"\r\n#include "grove_generic_analog_in_gen.h"\r\n#include "grove_relay_gen.h"\r\n\r\nextern GenericAIn *GenericAInA0_ins;\r\nextern GroveRelay *GroveRelayD0_ins;\r\n#endif\r\n', u'./Main.cpp': u'#include "wio.h"\n#include "suli2.h"\n#include "Main.h"\n\nvoid setup()\n{\n}\n\nvoid loop()\n{\n\n}\n'}
=> Saved into files
$ ls
Main.cpp Main.h ulb_helper.py
Modify ULB
See Main.h
first.
#ifndef __MAIN_H__
#define __MAIN_H__
#include "suli2.h"
#include "grove_generic_analog_in_gen.h"
#include "grove_relay_gen.h"
extern GenericAIn *GenericAInA0_ins;
extern GroveRelay *GroveRelayD0_ins;
#endif
These are all generated by the server according to the configuration map. As you can see, the code refers the GenericAInA0_ins
and GroveRelayD0_ins
, and their classes GenericAIn
and GroveRelay
. These are the class from the Grove drivers. To figure out what functions we can call, we need to find the corresponding driver.
All the Grove drivers are here: https://github.com/Seeed-Studio/Grove_Drivers_for_Wio
Another way to find out what functions we can call is, the output of the API : /v1/scan/drivers
, see the documentation here: http://seeed-studio.github.io/Wio_Link/#get-all-grove-drivers-39-information
Now modify the Main.cpp
file:
#include "wio.h"
#include "suli2.h"
#include "Main.h"
uint32_t time;
int light;
void setup()
{
time = millis();
light = 0;
}
void loop()
{
// Please note that, delay() will block the main event loop
// If you still need network communication, don't delay() for a long time.
if(millis() - time > 100) {
GenericAInA0_ins->read_analog(&light);
if (light < 100) {
GroveRelayD0_ins->write_onoff(1);
} else {
GroveRelayD0_ins->write_onoff(0);
}
time = millis();
}
}
In this example, if the value of light sensor is less than 100, the relay will be turned on, otherwise the relay will be turned off. This logic will run every 100 milliseconds.
Upload ULB
$ ./ulb_helper.py set https://cn.wio.seeed.io 9bfc9a8c9c2c975bb4b770ca0fd088b1
{'Main.cpp': '#include "wio.h"\n#include "suli2.h"\n#include "Main.h"\n\nuint32_t time;\nint light;\n\nvoid setup()\n{\n time = millis();\n light = 0;\n}\n\nvoid loop()\n{\n // Please note that, delay() will block the main event loop\n // If you still need network communication, don\'t delay() for a long time.\n if(millis() - time > 100) {\n GenericAInA0_ins->read_analog(&light);\n if (light < 100) {\n GroveRelayD0_ins->write_onoff(1);\n } else {\n GroveRelayD0_ins->write_onoff(0);\n }\n time = millis();\n }\n}\n', 'Main.h': '#ifndef __MAIN_H__\r\n#define __MAIN_H__\r\n#include "suli2.h"\r\n#include "grove_generic_analog_in_gen.h"\r\n#include "grove_relay_gen.h"\r\n\r\nextern GenericAIn *GenericAInA0_ins;\r\nextern GroveRelay *GroveRelayD0_ins;\r\n#endif\r\n'}
=> Posting contents...
=> Success!
Trigger the OTA
$ ./ulb_helper.py ota https://cn.wio.seeed.io 9bfc9a8c9c2c975bb4b770ca0fd088b1
=> Success! The OTA has been triggered.
{u'ota_msg': u'Notifying the node...[0]', u'ota_status': u'going'}
{u'ota_msg': u'Node has been notified...', u'ota_status': u'going'}
{u'ota_msg': u'Downloading the firmware...', u'ota_status': u'going'}
{u'ota_msg': u'Verifying the firmware...', u'ota_status': u'going'}
{u'ota_msg': u'Firmware updated.', u'ota_status': u'done'}
Now cover the light sensor, you will see the relay is turned on.