本博文目录;

  • 本博文目录;
  • 一、前言;
  • 二、机智云与其他平台有什么不一样;
  • 三、在机智云平台创建产品并自动生成代码;
  • 第一步:创建产品;
  • 第二步:自动生成代码;
  • 第三步:修改硬件代码;
  • 第四步:修改Android代码;
  • 五、下载;


一、前言;

在写这篇博文前,我希望这机智云专题的笔记可以帮助更多入门物联网智能家居的小伙伴,我是2016年广东省电子设计大赛开始接触机智云的产品的,一路上也算是看到了他们的迅速发展。所以,记下一些笔记来分享下怎么接入这个强大的、免费提供服务器的物联网平台给大家介绍。共勉!!!

  • 在当年还在大三的时候,嵌入式这种互联互通的在市面上还不是很常见的,直到阿里智能、百度dueros、京东微联和小米出来这个AI人工智能平台之后,整个物联网智能家居生态才真正地火热起来。我也是接入了好几个平台,感觉还是蛮好玩的;不得不说,是机智云这个平台开始带我走进物联网世界,阅读机智云的文档和相关物联网专有名词,不得不说,大学学的东西真少!至此,我准备建立一个新的博文篇,专门介绍接入机智云的方方面面,相信你一定会爱上她的。哈哈~

二、机智云与其他平台有什么不一样;


  • 我也是一个热爱学习的人,每天都要搞些新知识充电或者重温下旧知识写博文;在我接触许多的物联网平台,其共同的特点都是有免费提供设备的云服务的,像乐鑫云、安信可云、百度云、阿里物理套件和最近的开发快平台,尽管不完善某些功能。但是和设备通讯还是极速的,因为毕竟都几乎是MQTT协议。至于机智云为何会有一些与众不同呢?下面是我总结的几点:
  • [1] 自动生成代码,包括我们的常见的stm32主流系列,esp8266固件源代码;而且还有我们上位机的Androidios源代码,以及跨平台的APICloud SDK;
  • [2] 机智云开发者社区有很多的一些demo可以借鉴,经典的微信宠物屋,rgb七彩灯都是远程控制的;这些我后面都会详细为大家怎么实现;
  • [3] 说到认证和荣誉,每天在微信公众号可以看到官微在推文章,而且很出名的正点原子推出的stm32开发板也是在和机智云合作。
  • [4] 如果你是一名Android开发人员,不了解嵌入式开发的过程,你可以学习机智云提供的上位机的SDK参考,之后你就可以很轻松面对其他云的设备SDK,比如阿里的SDS服务提供的SDK接入,以及小米的插件化的SDK环境接入;而且可以自己琢磨下机智云的自动生成代码的源码,渗透下整个app的运作流程。
  • [5] 如果你是一名设备端开发人员,但是对设备接入服务器不熟悉,你可以去看下自动生成的esp8266的源代码,看下人家怎么写出标准的、高可行的代码;说白了,就是要学习人家的架构思想,编程逻辑;
  • [6] 这点没有什么好说的 ,在现在的资料开源的时代,我们可以借助一切,把自己的能力提升,而机智云免费开源的这些代码,就是对自己的职业发展的助力石。

三、在机智云平台创建产品并自动生成代码;


  • 先看看整体效果:

esp8266开发智能家居 基于esp8266的智能插座_esp8266开发智能家居


第一步:创建产品;

在任何一个服务器上面,要想开发一个设备,那必须要先在服务器注册一个设备,访问机智云的开发者中心点我访问,和其他的厂家一样,都是需要创建数据点和数据点类型。本篇文章主要讲的是一个定时的智能插座(说白了就是单路继电器),所以只需要注册以下几个数据点即可:

  • 注意数据点是一个产品的属性,当我们要控制设备或查询设备,都是通过数据点来操作的;

数据点名字

含义

取值范围

timerOpen

当定时器使能时候,设备倒时开的时间;仅仅当 isTimerOpen为true生效;

0~3600秒

lightOnOff

开关的下发

true:开;false:关

isTimerOpen

定时器的使能标志位

true:开;false:关

esp8266开发智能家居 基于esp8266的智能插座_自动生成代码_02


第二步:自动生成代码;


  • 我觉得,自动生成代码是最舒服的,因为不用自己搭建框架;也不用管数据怎么发送和接受,只需要在下发和上发的函数做自己的处理即可:

看到服务—–>MCU开发,我们选择soc方案,选择esp8266_32M,因为我们Gokit3拓展板用的是esp8266-12f模块,注意下面那个product key是从上面的基本信息复制下来的。

esp8266开发智能家居 基于esp8266的智能插座_esp8266开发智能家居_03


第三步:修改硬件代码;


  • 在机智云的Gokit3的拓展板上面,引出的脚有限;我仔细看看,只有一个脚是引出来了,是GPIO0,那我就准备用它自带的按键2来实现配网,而连接继电器那个是GPIO0,通过拓展版的原理图可以看到,按键二是连接到GPIO14的,所以,简化后的原理图就是这样的:

esp8266开发智能家居 基于esp8266的智能插座_esp8266开发智能家居_04


  • ①:增加GPIO口的驱动;

上面的图可以看到,我们继电器的是GPIO0,毫不疑问,我们首先初始化这个端脚:

//初始化GPIO
    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0);

  • ②: 机智云自动生成的代码是针对她的开发板GOkit3的,所以我们不需要增加按键驱动代码,我们上面看到是GPIO014作为按键,毫不疑问,我们只需要初始化这个端脚即可:注意我们进入一键配网的时候,要做出对应的状态,长按按键2,我这里做出的状态是继电器开关2次,表示成功进到一键配网的状态;
//仅仅定义 gpio14 按键中断
#define GPIO_KEY_NUM                            1                         
#define KEY_0_IO_MUX                            PERIPHS_IO_MUX_MTMS_U     
#define KEY_0_IO_NUM                            14                         
#define KEY_0_IO_FUNC                           FUNC_GPIO14               
LOCAL key_typedef_t * singleKey[GPIO_KEY_NUM];                            
LOCAL keys_typedef_t keys;

在我们的长按触发事件方法如下处理:

LOCAL void ICACHE_FLASH_ATTR keyLongPress(void)
{
    GIZWITS_LOG("#### key2 long press, airlink mode\n");
    //进入一键配网
    gizwitsSetMode(WIFI_AIRLINK_MODE);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0);
    os_delay_us(100000);
    //开关2次
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
    os_delay_us(100000);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0);
    os_delay_us(100000);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
    os_delay_us(100000);
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0);

}

我们希望短按也可以开关继电器,so,在我们的短按触发事件方法如下处理:

LOCAL void ICACHE_FLASH_ATTR keyShortPress(void) {

    if (isOpen) {
        isOpen = false;
        GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0); //关继电器
    } else {
        isOpen = true;
        GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);//开继电器
    }
}

  • ③: 我们现在注意力转移到这来gizwits_product.c文件,里面的gizwitsEventProcess()方法是我们处理收到手机指令处理,对比下我们的 数据点就明白了!
//开关指令
    case EVENT_lightOnOff:
            currentDataPoint.valuelightOnOff = dataPointPtr->valuelightOnOff;
            GIZWITS_LOG("Evt: EVENT_lightOnOff %d \n", currentDataPoint.valuelightOnOff)
            ;
            if (0x01 == currentDataPoint.valuelightOnOff) {
                //user handle
                GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 0);
            } else {
                //user handle
                GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
            }
            break;
   //定时器使能指令
        case EVENT_isTimerOpen:
            currentDataPoint.valueisTimerOpen = dataPointPtr->valueisTimerOpen;
            GIZWITS_LOG("Evt: EVENT_isTimerOpen %d \n", currentDataPoint.valueisTimerOpen)
            ;
            if (0x01 == currentDataPoint.valueisTimerOpen) {
                //user handle
                //if current is not at timer
                if (currentDataPoint.valuetimerOpen == 0
                        || currentDataPoint.valuetimerOpen < 0)
                    currentDataPoint.valueisTimerOpen=false;
                    os_timer_disarm(&os_timer);

            } else {

                os_timer_disarm(&os_timer);
                currentDataPoint.valuetimerOpen = 0;
            }

            break;
 //定时时间下发;注意此刻上报要把定时器使能开启置位1
        case EVENT_timerOpen:
            currentDataPoint.valuetimerOpen = dataPointPtr->valuetimerOpen;
            GIZWITS_LOG("Evt:EVENT_timerOpen %d\n",currentDataPoint.valuetimerOpen)
            ;
            //add
            currentDataPoint.valueisTimerOpen = true;//把定时器使能开启置位1
            os_timer_disarm(&os_timer);
            os_timer_setfn(&os_timer, (ETSTimerFunc *) (Led_Task_Run),
            NULL);
            os_timer_arm(&os_timer, 2000, true);//开启定时器,计数开始,反复测试只有2000才是接近一秒
            break;

  • ④、看看我们的定时器执行的任务,我们这里利用定时器每秒自动重载,达到我们APP下发的计数之后,执行开灯指令;
void Led_Task_Run() {
    GIZWITS_LOG("Led_Task_Run...\r\n");
    GIZWITS_LOG("Led_Task_Run:%d\r\n",currentDataPoint.valuetimerOpen);

    if (0x01 == currentDataPoint.valueisTimerOpen) {
        //启动定时器
        mCountTimes--;
        currentDataPoint.valuetimerOpen = mCountTimes / 60;
        if (currentDataPoint.valuetimerOpen == 0) {
            currentDataPoint.valuetimerOpen = 0;
            currentDataPoint.valueisTimerOpen = false;
            currentDataPoint.valuelightOnOff = false;
            //计数达到目标,继电器吸合
            GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
            os_timer_arm(&os_timer, 2000, true);
        }
    } else {
        currentDataPoint.valuetimerOpen = 0;
        currentDataPoint.valueisTimerOpen = false;
        os_timer_arm(&os_timer, 2000, true);
    }
}

  • ⑤:修改makeFile文件:因为自动生成的代码是没有OTA的地址烧录的,那么我们修改下即可:
BOOT?=new
APP?=1
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=6

  • ⑥:修改gizwits_protocol.c文件的宏定义:修改定时上报的间隔时间:
#define USER_TIME_MS 5000

第四步:修改Android代码;


  • 因为安卓代码是直接生成的,所以我们只需要修改下控制界面的UI即可;如下:

esp8266开发智能家居 基于esp8266的智能插座_esp8266开发智能家居_05


  • 需要注意的是,自动生成的代码下发定时时间时候,是可以看到具体时间的,毕竟拖动条嘛!这里的话,我准备用一个弹窗,然后用户选择确定时候,自动计算时间差下发给设备。具体的时间差算法如下:
/**
     * 返回一个将要的时间,单位是s
     *
     * @param temptimers 开始工作的时间四位数 格式 1025 表示 10:25
     * @return 将在这个时间之后启动
     */
    public static int creatTimers(String temptimers) {

        int returnTimers = 0;
        int times = Integer.parseInt(temptimers);
        Calendar mCalendar = Calendar.getInstance();
        //把当前时间转为 1234格式
        int NowTimes = mCalendar.get(Calendar.HOUR_OF_DAY) * 100 + mCalendar.get(Calendar.MINUTE);
        //如果设置定时的时间大于现在的时间 比如 当前是 10:23,设置的时间是 12:35
        if (NowTimes >= times) {
            returnTimers = 24 * 3600 - (creatMinute(NowTimes) - creatMinute(times));
        } else {
            returnTimers = (creatMinute(times) - creatMinute(NowTimes));
        }
        return returnTimers;
    }

    /**
     * @param afterTimes 多少分钟之后的时间点;范围无限
     * @return 15:25 表示15点25分
     */
    public static String creatAfterTime(int afterTimes) {

        String value = null;
        //先确定传来的数值有多少个小时,多少分钟
        int hour = afterTimes / 60;
        int minute = afterTimes % 60;

        Calendar mCalendar = Calendar.getInstance();
        //把当前时间转为 1234格式
        int NowHour = mCalendar.get(Calendar.HOUR_OF_DAY);
        int NowMinute = mCalendar.get(Calendar.MINUTE);

        if (NowHour + hour > 23)
            NowHour -= 24;

        if ((minute + NowMinute) > 0)
            value = (NowHour + hour) + ":" + (minute + NowMinute);
        else
            value = (NowHour + hour) + ":0" + (minute + NowMinute);

        return value;
    }


    private static int creatMinute(int timers) {

        int[] value = new int[4];
        value[0] = timers % 10000 % 1000 % 100 % 10; //个位
        value[1] = timers / 10 % 1000 % 100 % 10;//十位
        value[2] = timers / 100 % 100 % 10;//百位
        value[3] = timers / 1000 % 10;//千位
        return value[0] * 60 + value[1] * 600 + value[2] * 3600 + value[3] * 10 * 3600;

    }

五、下载;