假想一下,当你结束了一天繁重的工作带着惺忪的双眼,背着沉重的电脑包回到家里。一开灯,刺眼的冷白光芒迎面而来,本来就沉重的心情,彷佛被一层层寒气所萦绕。
时光机往后拨一下,当你晚上回家,打开门的时候,一束温暖的灯光,伴随着门的打开流露出来,有点像小学课本里,游子在家门不远处看到母亲打着灯笼的光若隐若现。
我们是新世纪的开发者,肩负着改变世界的重任。打造一款智能灯 App,改变用户对灯的认识,改善人们的生活环境是非常重要的。例如,用户早上起床时,伴随着闹钟,冷光灯亮起,走到厨房,自动启动照明;晚上回家后,暖光在开门前就已经亮起。
本教程假设您已经拥有了一款智能硬件产品,该产品可以是您从涂鸦硬件开发平台创建的,也可以是您在涂鸦智选(TuyaGo)平台购买的。查看详情
那么如何实现一款智能灯App呢?首先,您需要了解下智能灯的基础功能。
智能定时功能:可以按照日、周进行设计定时器,可以实现单次,循环定时,可以对分组进行设置定时。
远程控制功能:通过家用无线路由器组成的局域网与其他终端设备(手机、平板等)进行通讯,还可以远程遥控灯光操作,实现对灯光的开,关,调光,场景,彩光模式等控制。
色彩调节功能:通过色彩调节功能,可以实现多达 16777216 种颜色的调节。
地理围栏功能:智能灯控App可以为用户实现离家和到家模式。
智能音乐灯功能:可以通过手机音乐和灯结合在一起,实现灯随着音乐有节律的闪烁。
智能场景功能:通过专家精心调优出四大场景功能,可以实现柔光模式、缤纷模式、炫彩模式、斑斓模式。
办公场景:针对办公场景,智能灯具有白光调节模式,还拥有阅读模式的场景可以选择。
会客场景:可以采用休闲模式,调节气氛。
卧室场景:卧室场景推荐使用暖光模式。
唤醒场景:可以通过设置智能定时实现起床播放音乐,并唤醒音乐灯。
在涂鸦 IoT 平台的 App 工作台中 App 工作台 中点击 App SDK,点击 创建 App。
填写 App 相关信息,点击确认。
您可以根据实际需求选择需要的选择方案,支持多选,然后根据 Podfile 和 Gradle 进行 SDK 的集成。
点击获取密码,获取 SDK 的 AppKey,AppSecret,安全图片等信息。
在 Android Studio 中新建工程。
配置 build.gradle。
build.gradle 文件里添加集成准备中下载的 dependencies 依赖库。
android {
defaultConfig {
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}
packagingOptions {
pickFirst 'lib/*/libc++_shared.so' // 多个aar存在此so,需要选择第一个
}
}
dependencies {
implementation 'com.alibaba:fastjson:1.1.67.android'
implementation 'com.squareup.okhttp3:okhttp-urlconnection:3.14.9'
// Tuya Home 最新稳定版:
implementation 'com.tuya.smart:tuyasmart:3.20.0'
}
在根目录的 build.gradle 文件中增加 jcenter() 仓库
repositories {
jcenter()
}
说明:
- 涂鸦智能 3.10.0 之前的版本的 SDK 默认只支持 armeabi-v7a。
- 3.11.0 版本后已经将 armeabi-v7a、arm64-v8a 集成进 SDK,请将本地手动放入的 SDK 的相关 so 库移除,使用 SDK 中提供的。
- 如果集成新版本 so 库。请移除之前老版本手动集成的库,防止冲突或者代码版本不一致导致的问题。
- 如有其他平台需要可前往 GitHub 获取。
集成安全图片
点击 “下载安全图片” ——“安全图片下载” 下载安全图片。
在集成准备中点击“下载安全图片”。将下载的安全图片命名为 “t_s.bmp”,放置到工程目录的 assets 文件夹下。
在 AndroidManifest.xml 文件里配置 appkey 和 appSecret,在配置相应的权限等。
<meta-data
android:name="TUYA_SMART_APPKEY"
android:value="应用 Appkey" />
<meta-data
android:name="TUYA_SMART_SECRET"
android:value="应用密钥 AppSecret" />
在 proguard-rules.pro
文件配置相应混淆配置。
#fastJson
-keep class com.alibaba.fastjson.**{*;}
-dontwarn com.alibaba.fastjson.**
#mqtt
-keep class com.tuya.smart.mqttclient.mqttv3.** { *; }
-dontwarn com.tuya.smart.mqttclient.mqttv3.**
#OkHttp3
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-keep class okio.** { *; }
-dontwarn okio.**
-keep class com.tuya.**{*;}
-dontwarn com.tuya.**
在 Application 中初始化 SDK,确保所有进程都能初始化。以下为示例代码:
public class TuyaSmartApp extends Application {
@Override
public void onCreate() {
super.onCreate();
TuyaHomeSdk.init(this);
}
}
将 appId
和 appSecret
等信息配置在 AndroidManifest.xml 文件里,或者您也可以在初始化代码里初始化。
TuyaHomeSdk.init(Application application, String appkey, String appSerect)
在退出应用的时候调用以下接口注销掉涂鸦智能云连接。
TuyaHomeSdk.onDestroy();
在 debug 模式下可以开启 SDK 的日志开关,查看更多的日志信息,帮助快速定位问题。在 release 模式下建议关闭日志开关。
TuyaHomeSdk.setDebugMode(true);
在接入 照明控制 SDK 之前,您可以先了解一下 照明灯的DEMO,需要把DEMO跑起来,登录成功之后,再进行下列操作。照明控制 SDK 需要依赖 Home SDK 其中的一部分,本步骤也会介绍到依赖的这一部分。
// home sdk 依赖,注意,必须使用大于等于此版本的SDK
implementation 'com.tuya.smart:tuyasmart:3.20.0'
// 控制SDK依赖
implementation 'com.tuya.smart:tuyasmart-centralcontrol:1.0.2'
注意:
tuyasmart-centralcontrol
使用了 Kotlin 编译,需要引入 Kotlin 库确保其正常使用。如果您的项目中已引入kotlin的可忽略下面的配置。
Kotlin 接入
在根目录的build.gradle中引入kotlin插件的依赖。
buildscript {
ext.kotlin_version = '1.3.72'
dependencies {
...
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
在app的build.gradle中引入kotlin插件和kotlin包。
apply plugin: 'kotlin-android'
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
未使用标准控制指令时,设备控制 一般使用这种方式:
ITuyaDevice mDevice = TuyaHomeSdk.newDeviceInstance(String devId);
// 监听控制结果
mDevice.registerDevListener(new IDevListener() {
@Override
public void onDpUpdate(String devId, String dpStr) {
}
@Override
public void onRemoved(String devId) {
}
@Override
public void onStatusChanged(String devId, boolean online) {
}
@Override
public void onNetworkStatusChanged(String devId, boolean status) {
}
@Override
public void onDevInfoUpdate(String devId) {
}
});
mDevice.publishDps("{\"101\": true}", new IResultCallback() {
@Override
public void onError(String code, String error) {
Toast.makeText(mContext, "开灯失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onSuccess() {
Toast.makeText(mContext, "开灯成功", Toast.LENGTH_SHORT).show();
}
});
这种方式控制时,会发送 DPID,如 101、102 之类的给设备来控制。其中 101 就是这个设备定义的开关 DPID。
这么做的缺点是,如果另一个设备也有开关功能,但是不是101控制开关,你就需要传入不同的参数来控制。而当n个设备都有开关功能,但是却dpId都不同,就要写非常多的适配逻辑。
为了解决同一个功能定义的 ID 不同的问题,引入了标准指令的概念。标准指令就是特定功能的标准编号。如照明类设备的开灯功能,其标准指令一定是"switch_led"。发送控制指令switch_led,一定可以控制照明设备的开关。详情请参考 标准指令。
判断当前产品是否支持标准指令
根据产品 ID 判断当前产品是否支持标准指令。
使用标准指令需要判断当前设备是否支持标准指令控制,不支持的设备不可以使用该控制方式,只能使用之前的接口控制。
示例代码:
boolean isStandard = TuyaHomeSdk.getDataInstance().isStandardProduct("your_product_id");
其中的 productId 是产品 id,可从 DeviceBean
中获取。
在集成了此SDK之后,调用方式变化如下:
ITuyaDevice mDevice = TuyaHomeSdk.newDeviceInstance(String devId);
// 注意:这里方法是registerDeviceListener,注册的 Listener 是 IDeviceListener
tuyaDevice.registerDeviceListener(new IDeviceListener() {
@Override
public void onDpUpdate(String devId, Map<String, Object> dpCodeMap) {
}
@Override
public void onRemoved(String devId) {
}
@Override
public void onStatusChanged(String devId, boolean online) {
}
@Override
public void onNetworkStatusChanged(String devId, boolean status) {
}
@Override
public void onDevInfoUpdate(String devId) {
}
});
HashMap<String, Object> dpCodeMap = new HashMap<>();
dpCodeMap.put("switch_led", true);
// 发送标准指令
tuyaDevice.publishCommands(dpCodeMap, new IResultCallback() {
@Override
public void onError(String code, String error) {
Toast.makeText(mContext, "开灯失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onSuccess() {
Toast.makeText(mContext, "开灯成功", Toast.LENGTH_SHORT).show();
}
});
注意:标准指令使用方法
registerDeviceListener
注册监听, 非标准是registerDevListener
。
值得注意的是,目前不是所有设备都支持标准指令控制,后文会说明如何判断该设备是否支持标准指令控制。如果不支持的设备,而又必须使用标准控制,需要联系涂鸦适配。
所有标准指令都可以在涂鸦智能平台查找到,例如:
有了tuyaDevice.publishCommands
方法和上面的指令,就可以发送标准指令来控制设备。
涂鸦 IoT 平台上有很多品类的 IoT 设备,不同的品类在涂鸦平台上都有固定的编号(category)。例如,灯具(dj) 标准指令集 中 dj
是指灯具的 category
值。使用 category 字段可以判断当前设备是什么产品,来展示不同的面板。
此表格包含大多数支持的品类,具体可参见 IoT 平台。
品类 | category 值 |
---|---|
开关 | kg |
插座 | cz |
排插 | pc |
场景开关 | cjkg |
窗帘开关 | clkg |
灯具 | dj |
扫地机 | sd |
电茶壶 | bh |
香薰机 | xxj |
加湿器 | jsq |
空调 | kt |
空气净化器 | kj |
晾衣架 | lyj |
取暖器 | qn |
空调控制器 | ktkzq |
窗帘 | cl |
温控器 | wk |
风扇 | fs |
门磁传感器 | mcs |
水浸传感器 | sj |
温湿度传感器 | wsdcg |
PIR传感器 | pir |
震动传感器 | zd |
压力传感器 | ylcg |
亮度传感器 | ldcg |
烟雾报警传感器 | ywbj |
声光报警传感器 | sgbj |
CO2传感器 | co2bj |
CO传感器 | cobj |
pm2.5传感器 | pm2.5 |
燃气报警传感器 | rqbj |
sos传感器 | sos |
门锁 | ms |
通过产品 ID 获取产品的品类值的示例代码:
String category = TuyaHomeSdk.getDataInstance().getStandardProductConfig("your_product_id").category;
涂鸦照明设备同时存在v1和v2新旧两种固件,即使使用了标准指令,也需要开发两套控制逻辑。
因此对照明设备功能进行封装,封装了灯具设备的开关、工作模式切换、亮度控制、冷暖控制、彩光控制和四种情景模式的控制。
首先,创建ITuyaLightDevice对象,灯相关的方法均封装在此方法中。
ITuyaLightDevice lightDevice = new TuyaLightDevice(String devId);
该对象封装了灯的所有dp点,包括控制指令的下发和上报。
这里提供几个简单的调用示例:
// 创建lightDevice
ITuyaLightDevice lightDevice = new TuyaLightDevice("vdevo159793004250542");
// 注册监听
lightDevice.registerLightListener(new ILightListener() {
@Override
public void onDpUpdate(LightDataPoint dataPoint) { // 返回LightDataPoint,包含灯所有功能点的值
Log.i("test_light", "onDpUpdate:" + dataPoint);
}
@Override
public void onRemoved() {
Log.i("test_light", "onRemoved");
}
@Override
public void onStatusChanged(boolean status) {
Log.i("test_light", "onDpUpdate:" + status);
}
@Override
public void onNetworkStatusChanged(boolean status) {
Log.i("test_light", "onDpUpdate:" + status);
}
@Override
public void onDevInfoUpdate() {
Log.i("test_light", "onDevInfoUpdate:");
}
});
// 开灯
lightDevice.powerSwitch(true, new IResultCallback() {
@Override
public void onError(String code, String error) {
Log.i("test_light", "powerSwitch onError:" + code + error);
}
@Override
public void onSuccess() {
Log.i("test_light", "powerSwitch onSuccess:");
}
});
// 晚安场景
lightDevice.scene(LightScene.SCENE_GOODNIGHT, new IResultCallback() {
@Override
public void onError(String code, String error) {
Log.i("test_light", "scene onError:" + code + error);
}
@Override
public void onSuccess() {
Log.i("test_light", "scene onSuccess:");
}
});
// 设置颜色
lightDevice.colorHSV(100, 100, 100, new IResultCallback() {
@Override
public void onError(String code, String error) {
Log.i("test_light", "colorHSV onError:" + code + error);
}
@Override
public void onSuccess() {
Log.i("test_light", "colorHSV onSuccess:");
}
});
您可以在这一步中了解更多的 App SDK API,实现更丰富的 App 控制功能。
方法说明
/**
* 注册监听
*/
void registerLightListener(ILightListener listener);
其中,ILightListener回调如下:
public interface ILightListener {
/**
* 监听照明设备dp点变化
*
* @param dataPoint 该灯具所有dp点的状态
*/
void onDpUpdate(LightDataPoint dataPoint);
/**
* 设备移除
*/
void onRemoved();
/**
* 设备上下线
*/
void onStatusChanged(boolean online);
/**
* 网络状态
*/
void onNetworkStatusChanged(boolean status);
/**
* 设备信息更新例如name之类的
*/
void onDevInfoUpdate();
}
参数说明
值得说明的是LightDataPoint
对象,该对象封装了当前设备所有功能点。当功能点发生变化时,将会回调。每次回调的都会是完整的对象。
以下是该对象参数的具体含义:
public class LightDataPoint {
/**
* 开关
*/
public boolean powerSwitch;
/**
* 工作模式。
* <p>
* MODE_WHITE为白光模式;
* MODE_COLOUR为彩光模式;
* MODE_SCENE为情景模式;
*/
public LightMode workMode;
/**
* 亮度百分比,从0到100
*/
public int brightness;
/**
* 色温百分比,从0到100
*/
public int colorTemperature;
/**
* 颜色值,HSV色彩空间.
* <p>
* 其中H为色调,取值范围0-360;
* 其中S为饱和度,取值范围0-100;
* 其中V为明度,取值范围0-100;
*/
public LightColourData colorHSV;
/**
* 彩灯情景。
*
* SCENE_GOODNIGHT为晚安情景;
* SCENE_WORK为工作情景;
* SCENE_READ为阅读情景;
* SCENE_CASUAL为休闲情景;
*/
public LightScene scene;
}
灯共分为一路灯(仅有白光)、二路灯(白光+冷暖控制)、三路灯(仅有彩光模式)、四路灯(白光+彩光)、五路灯(白光+彩光+冷暖)。
这5种灯具在功能定义上有所区别,在开发相应的UI和控制时有所区别。
该方法可获取当前灯的类型。
/**
* 获取当前是几路灯
*
* @return {@link LightType}
*/
LightType lightType();
其中LightType中定义的类型有:
/**
* 白光灯,dpCode:bright_value
*/
TYPE_C,
/**
* 白光+冷暖,dpCode:bright_value + temp_value
*/
TYPE_CW,
/**
* RGB,dpCode:colour_data
*/
TYPE_RGB,
/**
* 白光+RGB,dpCode:bright_value + colour_data
*/
TYPE_RGBC,
/**
* 白光+冷暖+RGB,dpCode:bright_value + temp_value + colour_data
*/
TYPE_RGBCW
打开一个设备面板时,需要获取所有功能点值来展示。可通过此接口获取上面提到的LightDataPoint对象。
/**
* 获取灯所有功能点的值
*/
LightDataPoint getLightDataPoint();
控制灯的开关
方法说明
/**
* 开灯 or 关灯
*
* @param status true or false
* @param resultCallback callback
*/
void powerSwitch(boolean status, IResultCallback resultCallback);
参数说明
字段 | 含义 |
---|---|
status | true为开 |
resultCallback | 仅表示此次发送指令成功or失败,真正控制成功需要识别ILightListener中的dp变化 |
控制工作模式的切换。
方法说明
/**
* 切换工作模式
*
* @param mode 工作模式
* @param resultCallback callback
*/
void workMode(LightMode mode, IResultCallback resultCallback);
参数说明
字段 | 含义 |
---|---|
mode | 工作模式,其值有MODE_WHITE(白光), MODE_COLOUR(彩光), MODE_SCENE(情景模式) |
resultCallback | 仅表示此次发送指令成功or失败,真正控制成功需要识别ILightListener中的dp变化 |
调用示例
如切换到彩光模式:
lightDevice.workMode(LightMode.MODE_COLOUR, new IResultCallback() {
@Override
public void onError(String code, String error) {
Log.i("test_light", "workMode onError:" + code + error);
}
@Override
public void onSuccess() {
Log.i("test_light", "workMode onSuccess");
}
});
注意:部分灯具必须切换到对应的工作模式才可以控制,比如控制彩光,必须先切换到彩光模式才可以发颜色的值。
控制亮度
方法说明
/**
* 亮度控制。
*
* @param status 亮度的百分比,取值范围0-100
* @param resultCallback callback
*/
void brightness(int status, IResultCallback resultCallback);
参数说明
字段 | 含义 |
---|---|
status | 亮度的百分比 |
resultCallback | 仅表示此次发送指令成功or失败,真正控制成功需要识别ILightListener中的dp变化 |
控制灯的冷暖值
方法说明
/**
* 色温控制
*
* @param status 色温的百分比,取值范围0-100
* @param resultCallback callback
*/
void colorTemperature(int status, IResultCallback resultCallback);
参数说明
字段 | 含义 |
---|---|
status | 色温的百分比 |
resultCallback | 仅表示此次发送指令成功or失败,真正控制成功需要识别ILightListener中的dp变化 |
控制彩色灯的颜色
方法说明
/**
* 设置彩灯的颜色
*
* @param hue 色调 (范围:0-360)
* @param saturation 饱和度(范围:0-100)
* @param value 明度(范围:0-100)
* @param resultCallback callback
*/
void colorHSV(int hue, int saturation, int value, IResultCallback resultCallback);
切换彩灯的情景模式,目前共有四种模式:
方法说明
/**
* @param lightScene {@link LightScene}
* @param resultCallback callback
*/
void scene(LightScene lightScene, IResultCallback resultCallback);
code | 名称 | 数据类型 | 取值描述 | 说明 |
---|---|---|---|---|
switch_led | 开关 | Boolean | {} | |
work_mode | 模式 | Enum | {“range”:[“white”, “colour”, “scene”, “music”, “scene_1”, “scene_2”, “scene_3”, “scene_4”]} | |
bright_value | 亮度 | Integer | {“min”:25,“scale”:0,“unit”:"", “max”:255,“step”:1} | |
bright_value_v2 | 亮度 | Integer | {“min”:10,“scale”:0,“unit”:"", “max”:1000,“step”:1} | |
temp_value | 冷暖 | Integer | {“min”:0,“scale”:0,“unit”:"", “max”:255,“step”:1} | |
temp_value_v2 | 冷暖 | Integer | {“min”:0,“scale”:0,“unit”:"", “max”:1000,“step”:1} | |
colour_data | 彩光模式数 | Json | {} | |
colour_data_v2 | 彩光模式数 | Json | {} | |
scene_data | 情景模式数 | Json | {} | |
scene_data_v2 | 情景模式数 | Json | {} | |
flash_scene_1 | 柔光模式 | Json | {} | |
flash_scene_2 | 缤纷模式 | Json | {} | |
flash_scene_3 | 炫彩模式 | Json | {} | |
flash_scene_4 | 斑斓模式 | Json | {} | |
music_data | 音乐灯模式控制 | Json | {} | |
control_data | 调节dp控制 | Json | {} | |
countdown_1 | 倒计时 | Integer | {“unit”:"", “min”:0,“max”:86400,“scale”:0,“step”:1} | |
scene_select | 场景选择 | Enum | {“range”:[“1”, “2”, “3”, “4”, “5”]} | 旧版本 |
switch_health_read | 健康阅读开关 | Boolean | {} | 旧版本 |
read_time | 健康阅读-阅读时间设置 | Integer | {“unit”:“minute”, “min”:1,“max”:60,“scale”:0,“step”:1} | 旧版本 |
rest_time | 健康阅读-休息时间设置 | Integer | {“unit”:“minute”, “min”:1,“max”:60,“scale”:0,“step”:1} | 旧版本 |
该内容对您有帮助吗?
是我要提建议