# blinker-library
Blinker library for embedded hardware. Works with Arduino, ESP8266, ESP32.  

# What's Blinker
[Blinker](https://blinker.app/) is a platform with iOS and Android apps to control embedded hardware like Arduino. You can easily build graphic interfaces for all your projects by simply dragging and dropping widgets.  
  
[Blinker](https://blinker.app/) 是一个运行在 IOS 和 Android 上用于控制嵌入式硬件的应用程序。你可以通过拖放控制组件,轻松地为你的项目建立图形化控制界面。  

# Reference/参考
* [EN-英文](https://github.com/blinker-iot/blinker-doc/wiki/Blinker-Arduino-library-reference)  
* [CN-中文](https://github.com/blinker-iot/blinker-doc/wiki/Blinker-Arduino-%E5%BA%93%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C)  
* [CN-中文/官网](https://doc.blinker.app/?file=003-%E7%A1%AC%E4%BB%B6%E5%BC%80%E5%8F%91/02-Arduino%E6%94%AF%E6%8C%81)  
<!-- 
---  

# 目前支持的硬件
* Arduino boards
    - Arduino Uno, Duemilanove
    - Arduino Nano, Mini, Pro Mini, Pro Micro, Due, Mega
* 使用 [esp8266/arduino](https://github.com/esp8266/arduino) 的ESP8266  
* 使用 [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32) 的ESP32  
  
# 连接类型
* Bluetooth Smart (BLE 4.0)  
* WiFi  
* MQTT  
  
# 准备工作
开始使用前你需要做好如下准备:
* [Arduino IDE](https://www.arduino.cc/en/Main/Software) 1.6.12及更新版本
* 使用 Arduino IDE 的开发板管理器安装 [esp8266/arduino](https://github.com/esp8266/arduino)
* 按照 [安装说明](https://github.com/espressif/arduino-esp32#installation-instructions) 安装 [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
  
# Blinker接口函数
## 设备配置
### Blinker.begin()
使用 **Blinker.begin()** 来配置 Blinker:
```
Blinker.begin(...);
```
根据你使用的连接方式选择不同的参数用于配置Blinker  
  

BLE:
```
#define BLINKER_BLE  
#include <Blinker.h>  
  
void setup() {  
    Blinker.begin();  
}
```  
  
>串口蓝牙模块:  
>**Blinker.begin()** 将使用默认设置配置 Serial(默认使用软串口)   
>  
>Blinker.begin();// 默认设置: 数字IO 2(RX) 3(TX), 波特率 9600 bps  
>Blinker.begin(4, 5);// 设置数字IO 4(RX) 5(TX), 默认波特率 9600 bps  
>Blinker.begin(4, 5, 115200);// 设置数字IO 4(RX) 5(TX) 及波特率 115200 bps  
>  
>若配置时Blinker.begin(0, 1);  
>0 1对应硬串口的RX TX, 库会默认使用硬串口与BLE模块进行通信  
>Blinker.begin(15, 14);//Arduino MEGA中如15, 14对应硬串口Serial3  
>  
>注意使用软串口时:  
>使用Arduino MEGA时以下IO可以设置为RX: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69  
>使用Arduino Leonardo时以下IO可以设置为RX: 8, 9, 10, 11, 14, 15, 16  
  
WiFi:
```
#define BLINKER_WIFI  
#include <Blinker.h>  
  
void setup() {  
    Blinker.begin(ssid, pswd);  
}
```  
  
MQTT:
```
#define BLINKER_MQTT  
#include <Blinker.h>  
  
void setup() {  
    Blinker.begin(auth, ssid, pswd);  
}
```
> MQTT 支持的硬件: WiFiduino, WiFiduino32, ESP8266, ESP32  

**begin()** 主要完成以下配置:  
1.初始化硬件设置;  
2.连接网络并广播设备信息等待app连接;
## 连接管理
### Blinker.connect()
建立 **Blinker** 设备间连接并返回连接状态, 默认超时时间为10秒
```
bool result = Blinker.connect();  
  

uint32_t timeout = 30000;//ms  
bool result = Blinker.connect(timeout);
```
### Blinker.disconnect()
断开 **Blinker** 设备间连接
```
Blinker.disconnect();
```
### Blinker.connected()
返回 **Blinker** 设备间连接状态
```
bool result = Blinker.connected();
```
### Blinker.run()
此函数需要频繁调用以保持设备间连接及处理收到的数据, 建议放在 **loop()** 函数中
```
void loop() {
    Blinker.run();
}
```
## 数据管理
### Blinker.available()
检测是否有接收到数据
```
bool result = Blinker.available();
```
### Blinker.readString()
读取接收到的数据
```
String data = Blinker.readString();
```
`*读取数据最大为 256 字节`
### Blinker.print()
发送数据
```
Blinker.print(data);
```
发送一个Json数据, 如 {text1:data}
```
Blinker.print(text1, data);
```  
发送一个带单位的Json数据, eg: {"temp":"30.2 °C"}
```
Blinker.print("temp", 30.2, "°C");
```
>发送的Json数据可以在 Blinker APP 的 TEXT 组件中显示  

```
*发送数据最大为 128 字节  
*MQTT方式接入时, print需间隔1s以上  
例:  
Blinker.print("hello");  
Blinker.delay(1000);  
Blinker.print("world);  
```  

### Blinker.beginFormat() && Blinker.endFormat()
当使用 **beginFormat** 时, **print** 发送出的数据都将以 Json 格式存入发送数据中。 这个发送数据将在使用 **endFormat** 时发送出去。
```
Blinker.beginFormat();  
Blinker.print("Hello","Blinker");
Blinker.print("start","end");
Blinker.print("number",123);
Blinker.endFormat();
```
>使用 endFormat 后, 发送的 Json 数据: {"Hello":"Blinker","start":"end","number":123}  


### Blinker.notify()
使用 **notify** 时, 发送数据以感叹号开始, 将会发送消息通知到app, 否则将会发送Json数据到app  

发送通知
```
Blinker.notify("!notify");
```
发送Json数据, 如 {"notice":"notify"}
```
Blinker.notify("notify");
```

## App Widgets
### Blinker.wInit()
组件初始化, 建议在使用前初始化 **Button** 、**Slider** 、 **Toggle** 及 **RGB**
```
Blinker.wInit("ButtonName", W_BUTTON);  
Blinker.wInit("SliderName", W_SLIDER);  
Blinker.wInit("ToggleName", W_TOGGLE);  
Blinker.wInit("RGBName", W_RGB);//键词, 类型  
```
>类型:  
>W_BUTTON 按键  
>W_SLIDER 滑动条  
>W_TOGGLE 开关  
>W_RGB RGB调色板  
>以上四种组件数量限制为 16个/种

### Blinker.button() 
读取开关/按键数据, 按下(Pressed)时返回true, 松开(Released)时返回false
```
bool result = Blinker.button("Button1");
```
### Blinker.slider()
读取滑动条数据
```
uint8_t result = Blinker.slider("Slider1");
```
### Blinker.toggle() 
读取拨动开关数据, 打开(ON)时返回true, 关闭(OFF)时返回false
```
bool result = Blinker.toggle("Toggle1");
```
### Blinker.joystick()
读取摇杆数据
```
uint8_t result_X = Blinker.joystick(J_Xaxis);
uint8_t result_Y = Blinker.joystick(J_Yaxis);
```
### BlinkerButton  
按键组件在App中可以设置 按键/开关/自定义 三种模式,  
**按键** 模式下支持 点按/长按/释放(tap/pre/pup) 三个动作  
**开关** 模式下支持 打开/关闭(on/off) 两个动作  
**自定义** 模式下支持 自定义指令 发送  

初始化, 创建对象
```
#define BUTTON_1 "ButtonKey"

BlinkerButton Button1(BUTTON_1);
```
用于处理 **button** 收到数据的回调函数
```
void button1_callback(const String & state)
{
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    BLINKER_LOG2("get button state: ", state);
}
```
> 在回调函数中, **state** 的值为:  
> **按键** : 点按(tap)/长按(pre)/释放(pup)  
> **开关** : 打开(on)/关闭(off)
> **自定义** : 你设置的值  

在 **setup()** 中注册回调函数
```
Button1.attach(button1_callback);
```
> 也可以在初始化时注册回调函数:
> BlinkerButton Button1(BUTTON_1, button1_callback);  

#### Button1.icon();
Button1.color("#FFFFFF");
Button1.text("Your button name or describe");
Button1.print("on");
### BlinkerJoystick
### BlinkerRGB
### BlinkerSlider
### BlinkerNumber
### BlinkerText
### BUILTIN_SWITCH
### Blinker.ahrs()
开启手机 **AHRS** 功能
```
Blinker.attachAhrs();
```
读取 **AHRS** 数据
```
int16_t result_Yaw = Blinker.ahrs(Yaw);
int16_t result_Roll = Blinker.ahrs(Roll);
int16_t result_Pitch = Blinker.ahrs(Pitch);
```
关闭手机 **AHRS** 功能
```
Blinker.dettachAhrs();
```
### Blinker.gps()
刷新手机 **GPS** 功能
```
Blinker.freshAhrs();
```
读取 **GPS** 数据
```
String result_LONG = Blinker.gps(LONG);  
String result_LAT = Blinker.gps(LAT);
```
> LONG 经度  
> LAT 维度  

<!-- ### Blinker.rgb()
读取 **RGB** 数据
```
uint8_t result_R = Blinker.rgb("RGBKEY", R);
uint8_t result_G = Blinker.rgb("RGBKEY", G);
uint8_t result_B = Blinker.rgb("RGBKEY", B);
```
### Blinker.vibrate()
发送手机振动指令, 震动时间, 单位ms 毫秒, 数值范围0-1000, 默认为500
```
Blinker.vibrate();
Blinker.vibrate(255);  
```
## SWITCH
APP中默认 **SWITCH** 组件
### Blinker.switchAvailable()
是否收到APP发来 **SWITCH** 控制指令
```
bool result = Blinker.switchAvailable();
```
### Blinker.switchGet()
读取 **SWITCH** 状态, 打开(ON)时返回true, 关闭(OFF)时返回false
```
bool state = Blinker.switchGet();
```
### Blinker.switchUpdate()
发送 **SWITCH** 最新状态, 用户务必在执行完控制动作后返回
```
Blinker.switchUpdate();
```
### Blinker.switchOn()
设置 **SWITCH** 状态为打开, 会触发 **Blinker.switchAvailable()**
```
Blinker.switchOn();
```
### Blinker.switchOff()
设置 **SWITCH** 状态为关闭, 会触发 **Blinker.switchAvailable()**
```
Blinker.switchOff();
```
## NTP time  
> NTP 目前仅试用于WiFi/MQTT接入  
### Blinker.setTimezone()  
设置时区, 如: 北京时间为+8:00  
```
Blinker.setTimezone(8.0);
```
### Blinker.time()
获取当前ntp时间, 单位为秒(s)
```
uint32 times = Blinker.time();
```
### Blinker.second()
获取当前时间秒数, 单位为秒(s), 获取成功时值: 0-59, 获取失败时值: -1
```
int8_t sec = Blinker.second();
```
### Blinker.minute()
获取当前时间分钟数, 单位为分(m), 获取成功时值: 0-59, 获取失败时值: -1
```
int8_t min = Blinker.minute();
```
### Blinker.hour()
获取当前时间小时数, 单位为小时(h), 获取成功时值: 0-23, 获取失败时值: -1
```
int8_t hour = Blinker.hour();
```
### Blinker.wday()
获取当前时间为当周的日期, 单位为天(d), 获取成功时值: 0-6(依次为周日/一/二/三/四/五/六), 获取失败时值: -1
```
int8_t wday = Blinker.wday();
```
### Blinker.mday()
获取当前时间为当月第几天, 单位为天(d), 获取成功时值: 1-31, 获取失败时值: -1
```
int8_t mday = Blinker.mday();
```
### Blinker.yday()
获取当前时间为当年第几天, 单位为天(d), 获取成功时值: 1-366, 获取失败时值: -1
```
int16_t yday = Blinker.yday();
```
### Blinker.month()
获取当前时间为当年第几月, 单位为月(mon), 获取成功时值: 1-12, 获取失败时值: -1
```
int8_t month = Blinker.month();
```
### Blinker.year()
获取当前时间对应年, 单位为年(y), 获取成功时值: 201x, 获取失败时值: -1
```
int16_t year = Blinker.year();
```
## 设备延时
### Blinker.delay()
延时函数, 在延时过程中仍保持设备间连接及数据接收处理
```
Blinker.delay(500);
```
>*为了连接设备成功, 需要延时时务必使用该函数;  
>使用此函数可以在延时期间连接设备及接收数据并处理数据, 延时完成后才能执行后面的程序;  

## Bridge
**Bridge** 功能用于 **MQTT** 设备与设备间的通信(无需使用app进行控制).
### Blinker.bridge()
填入需要 **Bridge** 桥接通信设备的 **authKey** 建立桥接功能, 桥接成功将返回 true, 桥接失败返回 false.
```
char bridgeKey[] = "Your MQTT Secret Key of bridge to device";

bool state = Blinker.bridge(bridgeKey);
```
> 建立桥接通信的设备务必属于同一个用户的设备, 一个Diy设备最多可以与4个Diy设备建立桥接通信  

### Blinker.bridgeAvailable()
检测是否有接收到桥接设备发来的数据
```
char bridgeKey[] = "Your MQTT Secret Key of bridge to device";

bool result = Blinker.bridgeAvailable(bridgeKey);
```
### Blinker.bridgeRead()
读取接收到的数据
```
char bridgeKey[] = "Your MQTT Secret Key of bridge to device";

String data = Blinker.bridgeRead(bridgeKey);
```
`*读取数据最大为 256 字节`
### Blinker.bridgePrint()
发送数据
```
Blinker.print(data);
```
发送一个Json数据, 如 {text1:data}
```
char bridgeKey[] = "Your MQTT Secret Key of bridge to device";

Blinker.bridgePrint(bridgeKey, text1, data);
```  
发送一个带单位的Json数据, eg: {"temp":"30.2 °C"}
```
char bridgeKey[] = "Your MQTT Secret Key of bridge to device";

Blinker.bridgePrint(bridgeKey, "temp", 30.2, "°C");
```
>发送的Json数据可以在 Blinker APP 的 TEXT 组件中显示  

```
*发送数据最大为 128 字节  
*MQTT方式接入时, bridgePrint需间隔1min以上  
例:  
Blinker.bridgePrint(bridgeKey, "hello");  
Blinker.delay(60000);  
Blinker.bridgePrint(bridgeKey, "world);  
```  

### Blinker.bridgeBeginFormat()&&Blinker.bridgeEndFormat()
当使用 **beginFormat** 时, **bridgePrint** 发送出的数据都将以 Json 格式存入发送数据中。 这个发送数据将在使用 **endFormat** 时发送出去。
```
Blinker.bridgeBeginFormat();  
Blinker.bridgePrint(bridgeKey, "Hello","Blinker");
Blinker.bridgePrint(bridgeKey,"start","end");
Blinker.bridgePrint(bridgeKey, "number",123);
Blinker.bridgeEndFormat();
```
>使用 endFormat 后, 发送的 Json 数据: {"Hello":"Blinker","start":"end","number":123}  
>*MQTT方式接入时, 除间隔1min外建议使用 beginFormat/endFormat 进行数据发送  

## Cloud
### Blinker.cloudUpdate()
上传配置信息到云端
```
Blinker.cloudUpdate("Hello blinker!");
```
> 上传信息数据最大为 256 字节  

### Blinker.cloudGet()
拉取云端的配置信息
```
String cloud_data = Blinker.cloudGet();

BLINKER_LOG2("Blinker.cloudGet(): ", cloud_data);
```
## SMS短信
设备通过 **MQTT** 接入时可以使用 **Blinker.sms()** 默认向该设备所属用户注册对应的手机发送一条短信.
```
Blinker.sms("Hello blinker! Button pressed!");
```
>注: 每个用户短信使用限制为 10条/天/人, 20字/条  
>目前diy用户只能向设备所属用户注册对应的手机发送短信  
  
后期将增加功能,付费用户可以在app端设置10个短信接收手机号, 对其中一个手机号发送一条信息
```
char phone[] = "18712345678";
Blinker.sms("Hello blinker! Button pressed!", phone);
```

>**注意**  
>- 禁止发送互联网金融相关的所有内容,包括验证码、系统通知和营销推广短信  
>- 系统通知类短信不支持营销内容  
>- 禁止发送涉及:色情、赌博、毒品、党政、维权、众筹、慈善募捐、宗教、迷信、股票、移民、面试招聘、博彩、贷款、催款、信用卡提额、投资理财、中奖、抽奖、一元夺宝、一元秒杀、A货、整形、烟酒、交友、暴力、恐吓、皮草、返利、代开发票、代理注册、代办证件、加群、加QQ或者加微信、贩卖个人信息、运营商策反、流量营销等信息的短信  
>- 营销推广短信除上述禁止内容外,另不支持:保险、房地产、教育、培训、游戏、美容、医疗、会所、酒吧、足浴、助考、商标注册、装修、建材、家私、会展、车展、房展等信息的短信  
>- 如出现违法违规或者损害到相关他人权益的,平台将保留最终追究的权利!请各会员严格遵守规范要求,加强自身业务安全,健康发送短信  

## 天气查询
设备通过 **MQTT** 接入时可以使用 **Blinker.weather()** 查询天气情况.
```
String weather_default = Blinker.weather();//默认查询设备ip所属地区的当前时刻的天气情况

String weather_chengdu = Blinker.weather("chengdu");//查询成都市当前时刻的天气情况

String weather_beijing = Blinker.weather("beijing");//查询北京市当前时刻的天气情况
```

```
String location = "chengdu";//传入参数为对应城市拼音/英文
String weather = Blinker.weather(location);
```
**返回信息中字段及信息说明**  

| 参数 | 描述 | 示例 |
| - | - | - |
| fl | 体感温度,默认单位:摄氏度 | 23 |
| tmp | 温度,默认单位:摄氏度 | 21 |
| cond_code | 实况天气状况代码 | 100 |
| cond_txt | 实况天气状况描述 | 晴 |
| wind_deg | 风向360角度 | 305 |
| wind_dir | 风向 | 西北 |
| wind_sc | 风力 | 3 |
| wind_spd | 风速,公里/小时 | 15 |
| hum | 相对湿度 | 40 |
| pcpn | 降水量 | 0 |
| vis | 实况天气状况代码 | 100 |
| cloud | 云量 | 23 |

**天气代码对照表**  

| 代码 | 中文 | 英文 | 
| - | - | - | 
| 100 | 晴 | Sunny/Clear | 
| 101 | 多云 | Cloudy | 
| 102 | 少云 | Few Clouds |
| 103 | 晴间多云 | Partly Cloudy |
| 104 | 阴 | Overcast |
| 200 | 有风 | Windy |
| 201 | 平静 | Calm |
| 202 | 微风 | Light Breeze 
| 203 | 和风 | Moderate/Gentle Breeze |
| 204 | 清风 | Fresh Breeze |
| 205 | 强风/劲风 | Strong Breeze |
| 206 | 疾风 | High Wind, Near Gale |
| 207 | 大风 | Gale |
| 208 | 烈风 | Strong Gale |
| 209 | 风暴 | Storm |
| 210 | 狂爆风 | Violent Storm |
| 211 | 飓风 | Hurricane |
| 212 | 龙卷风 | Tornado |
| 213 | 热带风暴 | Tropical Storm |
| 300 | 阵雨 | Shower Rain |
| 301 | 强阵雨 | Heavy Shower Rain |
| 302 | 雷阵雨 | Thundershower |
| 303 | 强雷阵雨 | Heavy Thunderstorm |
| 304 | 雷阵雨伴有冰雹 | Thundershower with hail |
| 305 | 小雨 | Light Rain |
| 306 | 中雨 | Moderate Rain |
| 307 | 大雨 | Heavy Rain |
| 308 | 极端降雨 | Extreme Rain |
| 309 | 毛毛雨/细雨 | Drizzle Rain |
| 310 | 暴雨 | Storm |
| 311 | 大暴雨 | Heavy Storm |
| 312 | 特大暴雨 | Severe Storm |
| 313 | 冻雨 | Freezing Rain |
| 314 | 小到中雨 | Light to moderate rain |
| 315 | 中到大雨 | Moderate to heavy rain |
| 316 | 大到暴雨 | Heavy rain to storm |
| 317 | 暴雨到大暴雨 | Storm to heavy storm |
| 318 | 大暴雨到特大暴雨 | Heavy to severe storm |
| 399 | 雨 | Rain |
| 400 | 小雪 | Light Snow |
| 401 | 中雪 | Moderate Snow |
| 402 | 大雪 | Heavy Snow |
| 403 | 暴雪 | Snowstorm |
| 404 | 雨夹雪 | Sleet |
| 405 | 雨雪天气 | Rain And Snow |
| 406 | 阵雨夹雪 | Shower Snow |
| 407 | 阵雪 | Snow Flurry |
| 408 | 小到中雪 | Light to moderate snow |
| 409 | 中到大雪 | Moderate to heavy snow |
| 410 | 大到暴雪 | Heavy snow to snowstorm |
| 499 | 雪 | Snow |
| 500 | 薄雾 | Mist |
| 501 | 雾 | Foggy |
| 502 | 霾 | Haze |
| 503 | 扬沙 | Sand |
| 504 | 浮尘 | Dust |
| 507 | 沙尘暴 | Duststorm |
| 508 | 强沙尘暴 | Sandstorm |
| 509 | 浓雾 | Dense fog |
| 510 | 强浓雾 | Strong fog |
| 511 | 中度霾 | Moderate haze |
| 512 | 重度霾 | Heavy haze |
| 513 | 严重霾 | Severe haze |
| 514 | 大雾 | Heavy fog |
| 515 | 特强浓雾 | Extra heavy fog |
| 900 | 热 | Hot |
| 901 | 冷 | Cold |
| 999 | 未知 | Unknown |

## AQI查询
设备通过 **MQTT** 接入时可以使用 **Blinker.aqi()** 查询空气质量情况.
```
String aqi_default = Blinker.aqi();//默认查询设备ip所属地区的当前时刻的空气质量情况

String aqi_chengdu = Blinker.aqi("chengdu");//查询成都市当前时刻的空气质量情况

String aqi_beijing = Blinker.aqi("beijing");//查询北京市当前时刻的空气质量情况
```

```
String location = "chengdu";//传入参数为对应城市拼音/英文
String aqi = Blinker.aqi(location);
```
**返回信息中字段及信息说明**  

| 参数 | 描述 | 示例 | 
| - | - | - | 
|pub_time | 数据发布时间,格式yyyy-MM-dd HH:mm | 2017-03-20 12:30 |
| aqi | 空气质量指数,[AQI和PM25的关系](https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%94%E8%B4%A8%E9%87%8F%E6%8C%87%E6%95%B0) | 74 | 
| main | 主要污染物 | pm25 | 
| qlty | 空气质量,取值范围:优,良,轻度污染,中度污染,重度污染,严重污染,[查看计算方式](https://zh.wikipedia.org/wiki/%E7%A9%BA%E6%B0%94%E8%B4%A8%E9%87%8F%E6%8C%87%E6%95%B0) | 良 |
| pm10 | pm10 | 78 |
| pm25 | pm25 | 66 |
| no2 | 二氧化氮 | 40 |
| so2 | 二氧化硫 | 30 |
| co | 一氧化碳 | 15 |
| o3 | 臭氧 | 20 |  

## Debug
将这行代码添加到你的工程文件第一行, 以启用串口调试输出功能:
```
#define BLINKER_PRINTER Serial
```
在 `void setup()` 中初始化串口Serial :
```
Serial.begin(115200);
```
你可以用额外的硬件串口 (HardWareSerial) 或者软串口 (SoftWareSerial) 来调试输出 (你需要额外的适配器将该串口连接到你的电脑上).  
  
如果你想调试输出更多细节信息 :
```
#define BLINKER_PRINTER Serial
#define BLINKER_DEBUG_ALL  //add this behind
```
## LOG
开启调试输出 (Debug) 后可以使用 **BLINKER_LOG()** 打印输出调试信息:
```
BLINKER_LOG1("detail message 1");  
BLINKER_LOG2("detail message 1", " 2");  
BLINKER_LOG3("detail message 1", " 2", " 3");  
BLINKER_LOG4("detail message 1", " 2", " 3", " 4");  
BLINKER_LOG5("detail message 1", " 2", " 3", " 4", " 5");  
BLINKER_LOG6("detail message 1", " 2", " 3", " 4", " 5", " 6");  
```

# 感谢
[WebSockets](https://github.com/Links2004/arduinoWebSockets) - Blinker 用这个库建立了一个 websocket 服务器  
[Adafruit_MQTT_Library](https://github.com/adafruit/Adafruit_MQTT_Library) - Blinker 用这个库建立了一个 MQTT 客户端  
[ArduinoJson](https://github.com/bblanchon/ArduinoJson) - Blinker 用这个库解析 Json   -->