用多协议换采集器制作家用负氧离子除醛设备(带空气检测传感器)

标题用多协议换采集器制作家用负氧离子除醛设备(带空气检测传感器)

最近家装,各种材料堆砌,又想急着搬进去住,发现室内总是有味道,实在放心不下,于是网上搜了一大圈,都是甲醛检测治理,一次性也比较贵,具体效果怎么样,也无从验证。正好有朋友在做负氧离子睡眠机方面的研究,交流了一下,他强力推鉴我用负氧离子发生器来除醛,效果杠杠的。闲来无事,说干就干。
还是利用我自己搭建的阿里云平台架构,EMQ+TDEngine+NGINX

在这里插入图片描述
硬件照常祭出我的多协议网关控制器
在这里插入图片描述
这次主要是利用控制器的串口采集各种传感器信号,根据预设浓度参数实现IO口控制220V继电器,实现负氧离子发生器的自动工作,和新风系统的工作(后一步考虑找一下新风系统的协议,美国百朗的,哪位大侠有的话可以提供一个)
传感器的选择
PMSA003-C PM2.5攀藤传感器A0 激光 高精度 测雾霾粉尘
在这里插入图片描述
CO2传感器用了比较便宜的CCS811
在这里插入图片描述

甲醛传感器达特 DART WZ-S
在这里插入图片描述
继电器板不想重新画板在淘宝上采购了硬石科技的3.3V控制输入220V 5A的光电隔离继电器模块
在这里插入图片描述

一切准备就绪,开始撸代码

//ccs811 ECO2 tvoc
bool ccs811_get_results (ccs811_sensor_t* dev, 
                         uint16_t* iaq_tvoc, 
                         uint16_t* iaq_eco2, 
                         uint8_t*  raw_i, 
                         uint16_t* raw_v)
{
    if (!dev) return false;

    dev->error_code = CCS811_OK;
    
    if (dev->mode == ccs811_mode_idle)
    {       
        error_dev ("Sensor is in idle mode and not performing measurements.", 
                   __FUNCTION__, dev);
        dev->error_code = CCS811_DRV_WRONG_MODE;
        return false;
    }

    if (dev->mode == ccs811_mode_250ms && (iaq_tvoc || iaq_eco2))
    {       
        error_dev ("Sensor is in constant power mode, only raw data "
                   "are available every 250ms", 
                   __FUNCTION__, dev);
        dev->error_code = CCS811_DRV_NO_IAQ_DATA;
        return false;
    }    
  
    uint8_t data[8];

    // read IAQ sensor values and RAW sensor data including status and error id
    if (!ccs811_reg_read(dev, CCS811_REG_ALG_RESULT_DATA, data, 8))
    {
        error_dev ("Could not read sensor data.", __FUNCTION__, dev);
        dev->error_code |= CCS811_DRV_RD_DATA_FAILED;
        return false;
    }

    // check for errors
    if (data[CCS811_ALG_DATA_STATUS] & CCS811_STATUS_ERROR)
    {
        return ccs811_check_error_status (dev);
    }

    // check whether new data are ready, if not, latest values are read from sensor
    // and error_code is set
    if (!(data[CCS811_ALG_DATA_STATUS] & CCS811_STATUS_DATA_RDY))
    {
        debug_dev ("No new data.", __FUNCTION__, dev);
        dev->error_code = CCS811_DRV_NO_NEW_DATA;
    }

    // if *iaq* is not NULL return IAQ sensor values
    if (iaq_tvoc) *iaq_tvoc = data[CCS811_ALG_DATA_TVOC_HB] << 8 | data[CCS811_ALG_DATA_TVOC_LB];
    if (iaq_eco2) *iaq_eco2 = data[CCS811_ALG_DATA_ECO2_HB] << 8 | data[CCS811_ALG_DATA_ECO2_LB];
    
    // if *raw* is not NULL return RAW sensor data
    if (raw_i) *raw_i = data[CCS811_ALG_DATA_RAW_HB] >> 2;
    if (raw_v) *raw_v = (data[CCS811_ALG_DATA_RAW_HB] & 0x03) << 8 | data[CCS811_ALG_DATA_RAW_LB];
    
    return true;
}
//pasma003 pm2.5 pm10
void Pasm_Packet_Handle(uint8_t* pdatabuf, uint16_t datalen)
{
    uint8_t temp, tmp1;
    uint16_t a;
    int i;
    for (i = 0; i < datalen; i++) {
        temp = pdatabuf[i];

        if (temp == 0x42)
        {
            package_index = 0;
            PMSA_start = 1;
            whole_package[package_index++] = temp;
            continue;
        }
        if (PMSA_start == 1)
        {
            if (temp == 0x4d)
                PMSA_start = 2;
            else
            {
                package_index = 0;
                PMSA_start = 0;
                whole_package[0] = 0;
                whole_package[1] = 0;
                continue;
            }
        }

        if (PMSA_start == 2)
        {
            whole_package[package_index] = temp;
            package_index++;
        }
        if ((package_index >= PACKAGE_LEN) && (whole_package[0] == 0x42) && (whole_package[1] == 0x4d))
        {
            pasmhandle_package(whole_package);
            PMSA_start = 0;
            package_index = 0;
            whole_package[0] = 0;
            whole_package[1] = 0;
            continue;
        }
        if (package_index >= PACKAGE_LEN)
        {
            PMSA_start = 0;
            package_index = 0;
            whole_package[0] = 0;
        }
    }
    return;
}
//dart HCHO
void Dart_Packet_Handle(uint8_t *pdatabuf,uint16_t datalen)
{
    uint8_t temp,tmp1;
    uint16_t a;
    int i;
    for (i = 0; i < datalen; i++) {
        temp = pdatabuf[i];

        if (temp == 0xff)
        {
            DART_RX_NUM = 0;
            Dart_start = 1;
        }
        if (Dart_start == 1)
        {
            Dart_Data[DART_RX_NUM] = temp;
            DART_RX_NUM++;
        }

        if ((DART_RX_NUM >= 9) && (Dart_Data[0] == 0xff) && (Dart_Data[1] == 0x86))
        {

            a = (Dart_Data[2] * 256 + Dart_Data[3]);
            if (a >= 5000)a = 5000;
            Dart_hcho_rev = a;
            ESP_LOGI(DART_TAG, "HCHO:%d\n", Dart_hcho_rev);
            SetDartDataValue(Dart_hcho_rev);
            Dart_start = 0;
            DART_RX_NUM = 0;
            Dart_Data[0] = 0;
            Dart_Data[1] = 0;
            continue;
        }
        if ((DART_RX_NUM >= 9) && (Dart_Data[0] == 0xff) && (Dart_Data[1] == 0x17))
        {

            a = (Dart_Data[4] * 256 + Dart_Data[5]);
            if (a >= 5000)a = 5000;
            Dart_hcho_rev = a;
            printf("HCHO:%d\n", Dart_hcho_rev);
            SetDartDataValue(Dart_hcho_rev);
            Dart_start = 0;
            DART_RX_NUM = 0;
            Dart_Data[0] = 0;
            Dart_Data[1] = 0;
            continue;
        }
        if (DART_RX_NUM >= 9)
        {
            Dart_start = 0;
            DART_RX_NUM = 0;
            Dart_Data[0] = 0;
        }
    }
    return;
}
//mqtt publish
void air_sense_mqtt(void* pvParameters)
{
    int ret1 = 0,ret2=0;
    uint16_t hcho;
    uint16_t pm25,pm10,pm1;
    uint16_t deviceid[3];
    char date_str[20];
    char time_str[20];
    cJSON* root = NULL;
    cJSON* subroot = NULL;
    char* pp;
    // wait for time to be set
    time_t now = 0;
    //struct tm timeinfo = { 0 };
    struct tm now_time = { 0 };
    TickType_t last_wakeup = xTaskGetTickCount();
    GetChipID();
    deviceid[0] = (mac_addr[1] << 8) | mac_addr[0];
    deviceid[1] = (mac_addr[3] << 8) | mac_addr[2];
    deviceid[2] = (mac_addr[5] << 8) | mac_addr[4];

    while (1)
    {
        // get environmental data from another sensor and set them
        // ccs811_set_environmental_data (sensor, 25.3, 47.8);

        // get the results and do something with them
        ret1=GetDartDataValue(&hcho);
        ret2=GetPMSA003Value(&pm25, &pm10, &pm1);
        if(ret1&&ret2)
        {

            printf("%.3f ESP32AIR Sensor periodic: hcho %d ppb, pm25 %dμg/m3  pm10 %dμg/m3  pm1 %dμg/m3 \n",
                (double)sdk_system_get_time() * 1e-3, hcho, pm25,pm10,pm1);

#if 1	
            time(&now);
            //localtime_r(&now, &timeinfo);
            localtime_r(&now, &now_time);

            sprintf(date_str, "%d-%d-%d", now_time.tm_year + 1900, now_time.tm_mon + 1, now_time.tm_mday);
            sprintf(time_str, "%d:%d:%d", now_time.tm_hour, now_time.tm_min, now_time.tm_sec);
            root = cJSON_CreateObject();//创建一个机器人状态的JSON对象
            subroot = cJSON_CreateObject();//subroot是下面的一个嵌入对象
            cJSON_AddStringToObject(subroot, "SensorType", "ESP32_AIR");
            cJSON_AddStringToObject(subroot, "DATE", date_str);
            cJSON_AddStringToObject(subroot, "TIME", time_str);
            cJSON_AddNumberToObject(subroot, "DEVICEID0", deviceid[0]);
            cJSON_AddNumberToObject(subroot, "DEVICEID1", deviceid[1]);
            cJSON_AddNumberToObject(subroot, "DEVICEID2", deviceid[2]);
            cJSON_AddNumberToObject(subroot, "Addr", 1);
            cJSON_AddNumberToObject(subroot, "HCHO", hcho);
            cJSON_AddNumberToObject(subroot, "PM25", pm25);
            cJSON_AddNumberToObject(subroot, "PM10", pm10);
            cJSON_AddNumberToObject(subroot, "PM1", pm1);
            cJSON_AddItemToObject(root, "RealAIR", subroot);
            pp = cJSON_Print(root);
            if (NULL == pp)
            {
                printf("cjson create fail\r\n");
                cJSON_Delete(root);
                return;
            }
            printf("real sensordata ESP_AIR:%s", pp);
            esp_mqtt_client_publish(g_mqtt_client, SENSOR_ESP32_AIR_REAL_DATA_TOPIC, pp, 0, 0, 0);
            //strcpy(csensorSOILPayloadStr,pp);
            cJSON_Delete(root);//最后将root根节点删除
            cJSON_free(pp);//释放result的空间,必须要有,要不然内存里会失去一段空间,最后系统崩溃	
            pp = NULL;
#endif
        }
        // passive waiting until 1 second is over
        vTaskDelayUntil(&last_wakeup, 30000 / portTICK_PERIOD_MS);
    }
}

监控界面采用了Grafana直接读取TDEngine数据,实现了极少的编程,界面效果还不错
在这里插入图片描述
作为理科生,多动手DIY可以防止老年痴呆,Fighting!

猜你喜欢

转载自blog.csdn.net/superxxd/article/details/107555361
今日推荐