树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制

树莓派mqtt协议连接阿里云物联网平台(二)

树莓派配置

硬件连接 i2c1 连接 AM2320温湿度传感器。
i2c0 连接 GY30-BH1750光强传感器。
用到两个库
一个是paho.mqtt.embedded-c-master.zip github上维护的c语言版本的mqtt协议库。链接
另一个是 博通的io操作库 bcm2835-1.68.tar.gz 链接

我的工程里并没有编译成so,我直接把源码里用的c文件复制过来了。
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第1张图片
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第2张图片
还有bcm2835 库有个宏 定义了i2c1 ,默认i2c0 是不编译的,我用了i2c0,库函数让我改了。

AM2320 读取函数

int get_am2320_data(int *temperature,int *himudity)
{
    uint8_t w_temp_data[AM2320_CMD_LEMGTH] = {0}; 
    uint8_t r_temp_data[AM2320_TEMP_RETURN_LENGTH] = {0};   

    iot_info("run get data from am2320\n");

    if (!bcm2835_init())
    {
        iot_error("bcm2835_init failed. Are you running as root??\n");
        return FAILURE;
    }
   
    if (!bcm2835_i2c_begin(I2C_1))
    {
        iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
	    return FAILURE;
    }
    bcm2835_i2c_setSlaveAddress(I2C_1,AM2320_DEVICE_ADDR);
    bcm2835_i2c_set_baudrate(I2C_1,AM2320_BAUDRATE);

    bcm2835_i2c_write(I2C_1,NULL,0); //wark up
    usleep(30*1000);
    w_temp_data[0] = AM2320_FUNCTION_CODE;
	w_temp_data[1] = AM2320_TEMP_HUMIDITY_ADDR;
	w_temp_data[2] = AM2320_TEMP_HUMIDITY_LENGTH;

    bcm2835_i2c_write(I2C_1,w_temp_data,AM2320_CMD_LEMGTH);
    usleep(30*1000); 
    bcm2835_i2c_read(I2C_1,r_temp_data,AM2320_TEMP_RETURN_LENGTH);
 
    *himudity = (((r_temp_data[2] << 8) | (r_temp_data[3])) & 0xffff);
    *temperature = (((r_temp_data[4] << 8)| (r_temp_data[5])) & 0xffff);
    bcm2835_i2c_end(I2C_1);   
    bcm2835_close();
    return SUCCESS;
}

BH1750 读取函数

int get_light_value(uint16_t *light_value)
{
    uint8_t r_light_data[2] = {0};
    uint8_t high_mode = BH_HMODE_RESOLUTION;

    iot_info("get_light_value now\n");
    if (!bcm2835_init())
    {
        iot_error("bcm2835_init failed. Are you running as root??\n");
        return FAILURE;
    }
   
    if (!bcm2835_i2c_begin(I2C_0))
    {
        iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
	    return FAILURE;
    }

    bcm2835_i2c_setSlaveAddress(I2C_0,BH1750_DEVICE_ADDR);
    bcm2835_i2c_set_baudrate(I2C_0,BH1750_BAUDRATE);

    bcm2835_i2c_write(I2C_0,&high_mode,1);
    usleep(180 * 1000);
    bcm2835_i2c_read(I2C_0,r_light_data,2);
       
    bcm2835_i2c_end(I2C_0);   
    bcm2835_close();

    *light_value = ((r_light_data[0] << 8) | r_light_data[1]);
    return SUCCESS;
}

int init_bh1750()
{
    uint8_t power_on = BH_POWER_ON;
    uint8_t reset = BH_RESET;
    iot_info("init_bh1750 now\n");
    if (!bcm2835_init())
    {
        iot_error("bcm2835_init failed. Are you running as root??\n");
        return FAILURE;
    }
      iot_info("init_bh1750 now\n");
    if (!bcm2835_i2c_begin(I2C_0))
    {
        iot_error("bcm2835_i2c_begin failed. Are you running as root??\n");
	    return FAILURE;
    }
   
    bcm2835_i2c_setSlaveAddress(I2C_0,BH1750_DEVICE_ADDR);
    bcm2835_i2c_set_baudrate(I2C_0,BH1750_BAUDRATE);
    
    bcm2835_i2c_write(I2C_0,&power_on,1);
    usleep(10 * 1000);
    bcm2835_i2c_write(I2C_0,&reset,1);
       
    bcm2835_i2c_end(I2C_0);   
    bcm2835_close();
    return SUCCESS;
}

还有个问题,我在几个线程里操作 博通这个库,如果抢占资源,会出现段错误,所以要保证一个时间点只要一个线程去操作博通这个库。这里用到了线程锁。

void *get_sensor_data_function(void *arg)
{
    int temp;
    int himudity;
    uint16_t light_value;
    int ret = 0;

    pthread_mutex_lock(&m_mutex);
    init_bh1750();
    pthread_mutex_unlock(&m_mutex);
    while (1){
        
        cJSON * root =  cJSON_CreateObject();
        cJSON * item =  cJSON_CreateObject();
        pthread_mutex_lock(&m_mutex);
        get_am2320_data(&temp,&himudity);
        pthread_mutex_unlock(&m_mutex);
       
        pthread_mutex_lock(&m_mutex);
        get_light_value(&light_value);
        pthread_mutex_unlock(&m_mutex);

        //iot_info("get_am2320_data temp = %d himudity = %d\n",temp,himudity);
        //iot_info("get_bh1750_data light = %d\n",light_value);
        //iot_info("get ali connect status  = %s\n",Iot_mqtt.iotstatus == IOT_STATUS_CONNECT ? "Connect" : "Disconect");

        cJSON_AddItemToObject(root,"method",cJSON_CreateString("thing.event.property.post"));
        cJSON_AddItemToObject(root,"id",cJSON_CreateString("01406633"));
        cJSON_AddItemToObject(root,"params",item);
        cJSON_AddItemToObject(item,"RoomTemp",cJSON_CreateNumber((float)temp/10.0));
        cJSON_AddItemToObject(item,"RoomHumidity",cJSON_CreateNumber((float)himudity/10.0));
        cJSON_AddItemToObject(item,"RoomLight",cJSON_CreateNumber((light_value * 10)/12));
        cJSON_AddItemToObject(root,"version",cJSON_CreateString("1.0.0"));

        char *payload_data = cJSON_Print(root);
        //iot_info("payload data = %s\n",payload_data); 

        if (Iot_mqtt.iotstatus == IOT_STATUS_CONNECT){

            ret = mqtt_data_write(payload_data,strlen(payload_data),0);
        }   
        iot_info("payload sensor data  to ali yun %s.\n",ret == 0 ? "Success" : "fail"); 
        sleep(3);
    }

mqtt移植,打开我们下载的paho.mqtt.embedded-c-master文件,里面用到的文件就那几个,MQTTPacket/src ,
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第3张图片
这两个文件
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第4张图片
还有两个文件
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第5张图片
工程里iot_mqtt.c是登录文件。

void iot_mqtt_init(Cloud_MQTT_t *piot_mqtt) 
{
    memset(piot_mqtt, '\0', sizeof(Cloud_MQTT_t));

    memcpy(piot_mqtt->sub_topic, MQTT_SUB_TOPIC,strlen(MQTT_SUB_TOPIC));	
    iot_info("subscribe:%s\n", piot_mqtt->sub_topic);

    memcpy(piot_mqtt->pub_topic, MQTT_PUSH_TOPIC,strlen(MQTT_PUSH_TOPIC));	
    iot_info("pub:%s\n", piot_mqtt->pub_topic);
    piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb;
}

void MQTTMessageArrived_Cb(MessageData* md)
{
    MQTTMessage *message = md->message; 

    Cloud_MQTT_t *piot_mqtt = &Iot_mqtt;

    if (NULL != piot_mqtt->DataArrived_Cb) {
        piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
    }
}

int mqtt_device_connect(Cloud_MQTT_t *piot_mqtt)
{
    int ret = 0;
    NewNetwork(&piot_mqtt->Network);
    iot_info("topic = %s\n", piot_mqtt->sub_topic);
    ret = ConnectNetwork(&piot_mqtt->Network, MQTT_HOST, (int)MQTT_PORT);	
    if (ret != 0) {
        iot_error("mqtt connect network fail \n");
        ret = CONNECT_NET_ERROR;
        goto error;
    }
    MQTTClient(&piot_mqtt->Client, &piot_mqtt->Network, 1000, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;

    if (piot_mqtt->willFlag) {
        data.willFlag = 1;
        memcpy(&data.will, &piot_mqtt->will, sizeof(MQTTPacket_willOptions));
    } else {
        data.willFlag = 0;
    }
    data.MQTTVersion = 3;
    data.clientID.cstring = MQTT_CLIENT_ID;
    data.username.cstring = MQTT_USER;
    data.password.cstring = MQTT_PASS;
    data.keepAliveInterval = 30;
    data.cleansession = 1;
    
    ret = MQTTConnect(&piot_mqtt->Client, &data);
    if (ret) {
        iot_error("mqtt connect broker fail \n");
        iot_error("rc = %d\n", ret);
        ret = MQTT_CONNECT_ERROR;
        goto error;
    }
    ret = MQTTSubscribe(&piot_mqtt->Client, piot_mqtt->sub_topic, opts.qos, MQTTMessageArrived_Cb);
    if (ret) {
        iot_error("mqtt subscribe fail \n");
        ret = MQTTSUBSCRIBE_ERROR;
        goto error;
    }
    Iot_mqtt.iotstatus = IOT_STATUS_CONNECT;
    iot_info("connect %s %s\n", MQTT_HOST,ret == 0 ? "Success" : "failure");
    return CONNECT_SUCCESS;
error:
    return ret;
}

树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第6张图片
登录用的host port 以及用户名 密码 clinet_ID 我直接代码里写死的,这里根据上篇讲到的那个product_key device_name 还有那个DeviceSecret来生成的,网上有个工具,复制进去生成如下:
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第7张图片
连接到服务器,可以在后台看见设备上线了。
树莓派上传数据到云端用的函数为

int mqtt_data_write(char *pbuf, int len, char retain)
{
    Cloud_MQTT_t *piot_mqtt = &Iot_mqtt; 
    int ret = 0;
    MQTTMessage message;
    char my_topic[128] = {0};

    strcpy(my_topic, piot_mqtt->pub_topic);

    //iot_info("publish topic is :%s\r\n", my_topic);
    //iot_info("mqtt tx len = %d\r\n", len);
    message.payload = (void *)pbuf;
    message.payloadlen = len;
    message.dup = 0;
    message.qos = QOS0;
    if (retain) {
        message.retained = 1;
    } else {
        message.retained = 0;
    }

    ret = MQTTPublish(&piot_mqtt->Client, my_topic, &message);	//发布一个主题
    return ret;
}

这里的topic 就是我们前一篇讲的,/sys/a1HozAJNWVx/raspberrypi/thing/event/property/post
但是上传数据要用JSON格式,所以工程里添加了CJSON库。


        cJSON_AddItemToObject(root,"method",cJSON_CreateString("thing.event.property.post"));
        cJSON_AddItemToObject(root,"id",cJSON_CreateString("01406633"));
        cJSON_AddItemToObject(root,"params",item);
        cJSON_AddItemToObject(item,"RoomTemp",cJSON_CreateNumber((float)temp/10.0));
        cJSON_AddItemToObject(item,"RoomHumidity",cJSON_CreateNumber((float)himudity/10.0));
        cJSON_AddItemToObject(item,"RoomLight",cJSON_CreateNumber((light_value * 10)/12));
        cJSON_AddItemToObject(root,"version",cJSON_CreateString("1.0.0"));

        char *payload_data = cJSON_Print(root);
        iot_info("payload data = %s\n",payload_data); 

这里的id随便写,app打印出来的格式为
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第8张图片
这样云端就会收到设备端的数据了。
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第9张图片
树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第10张图片

工程是cmake 管理的。下载后cmake CMakeLists.txt ;make命令编译,
运行sudo ./iotApp 即可。

树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第11张图片

树莓派mqtt协议连接阿里云物联网平台,手机端获取数据并控制_第12张图片
源码

你可能感兴趣的:(阿里云,mqtt,linux,物联网,传感器)