嵌入式软件如何记录用户行为?

原创 嵌入式大杂烩 2024-07-13 11:39

记录用户行为的意义?

很多互联网产品都会有数据分析的后台,比如,本公众号的一些数据分析:

通过后台的一些数据分析,我可以知道本公众号读者的一些年龄分布、地域分布、对哪些文章比较感兴趣等信息。

这些数据一定程度上对我之后生产内容有一定的启发。这些数据就是微信公众号把我们的一些用户信息、阅读公众号的一些行为给记录下来,并形成图表等形式展现出来。

特别是To C的消费类电子产品,用户数量较大,用户对设备的使用习惯对产品经理们之后的决策、工程师之后的优化方向很有帮助。

线上的嵌入式设备能记录用户的行为,能够帮助我们深入了解用户的行为模式,进而实现个性化推荐、故障预测、用户体验优化等目标。

比如:

  • • 通过分析大量的用户使用功能A的频次最多,那么功能A的bug能修复就尽量修复好,哪怕是一些比较偏门的路径,因为这个功能好用与否可能关乎到用户对于这个产品地评价。

  • • 通过监控用户在执行哪些操作时,触发了一些异常,这对于之后地优化起到了指导的方向。

  • • 用户可能在夜间的时候没有使用设备的习惯,那对于夜间的一些有声音的预约操作是不是可以通过各种策略提前预防到这种情况,防止打扰用户休息。

具体到各个行业:

  • • 智能家居行业。通过智能门锁、智能照明等设备的埋点数据,分析用户的日常行为习惯,以优化家居环境的智能化管理。

  • • 工业自动化。通过埋点数据收集生产过程中的关键参数,进行质量控制和数据分析,确保产品质量的稳定性。

  • • 医疗健康。通过分析用户的日常健康数据(如步数、心率、睡眠质量等),提供个性化的健康管理建议。

  • • 智能交通。在智能交通信号灯中嵌入埋点,根据实时交通流量调整信号灯配时,提高道路通行效率。

  • • 物联网。通过对物联网设备收集的海量数据进行分析,预测设备的运行趋势和潜在故障,提前采取措施进行预防和维护。

记录用户的行为,有个专业一点的词,叫做埋点

嵌入式埋点就是在嵌入式设备中预设一些数据采集点(即“埋点”),当特定事件发生时(如用户点击某个按钮、观看某个节目),这些埋点会自动记录并上传相关数据到服务器进行分析。

如何进行数据埋点?

整个数据分析的步骤大致如下:

  • • 事件定义与管理:首先,在嵌入式设备中定义和管理数据采集点,即“埋点”。这些埋点可以配置为在用户点击、交互等事件发生时触发数据采集。

  • • 数据采集与传输:当事件发生时,嵌入式设备将相关数据存储起来并通过网络传输到数据采集服务器。这里,可以使用HTTP请求、WebSocket、MQTT等协议实现数据的实时传输。

  • • 数据处理与分析:在服务器端,使用大数据处理工具对收集到的数据进行实时处理和分析。通过分析用户的点击行为、观看习惯等,可以建立用户行为模型,实现个性化推荐和安全监控等应用。

这里我们着重分享事件定义与管理的例子:

我们基于Linux C,使用POSIX线程(pthread)来创建单独的线程,并使用POSIX消息队列来接收来自其他线程的开机次数及按键埋点事件。同时,我们将使用cJSON库来处理JSON数据,以及标准文件操作来记录数据到tracking.log文件中。

本例子源码可以在本公众号回复关键词:埋点例子,进行获取。

本例子源码可以在本公众号回复关键词:埋点例子,进行获取。

本例子源码可以在本公众号回复关键词:埋点例子,进行获取。

1、相关头文件

#include   
#include   
#include   
#include 
#include   
#include   
#include   
#include   
#include   
#include "cJSON.h"

2、埋点事件数据结构

    // 埋点类型
enum track_event_type
{
    TRACK_EVENT_TYPE_BOOT,
    TRACK_EVENT_TYPE_BUTTON,
    TRACK_EVENT_TYPE_MAX,
};

// 公共埋点信息
struct track_event_common_info
{
    char dev_name[32];// 设备名称
    char serial_num[32];// 设备序列号
    char timestamp[64];// 时间戳
};

// 启动事件信息
struct track_event_info_boot
{
    unsignedint cnt;// 开机次数
};

// 按键事件信息
struct track_event_info_button
{
    unsignedchar button_num;// 按键号
    unsignedchar button_type;// 按键类型,长按 or 短按
};

// 当前的埋点事件信息
union track_event_info
{
    struct track_event_info_boot track_boot;
    struct track_event_info_button track_button;
};

// 埋点事件体
struct tracking_event
{
    enum track_event_type event_type;
    union track_event_info event_info;

    struct track_event_common_info *event_common_info;
};  

3、消息队列初始化、清除接口

#define QUEUE_NAME  "/mq0" 
mqd_t g_mqd;

intinit_mq(void)
{
    struct mq_attr attr;

    attr.mq_flags = 0;
    attr.mq_maxmsg = 10;// 最大消息数  
    attr.mq_msgsize = sizeof(struct tracking_event);// 消息最大大小 
    attr.mq_curmsgs = 0;// 当前队列中的消息数(由系统维护)  

    g_mqd = mq_open(QUEUE_NAME, O_CREAT | O_RDWR,0777,&attr);
    if(g_mqd == (mqd_t)-1)
    {
        perror("mq_open");
        exit(EXIT_FAILURE);
    }

    return 0;
}

voidcleanup_mq(void)
{
    mq_close(g_mqd);
    mq_unlink(QUEUE_NAME);
}

4、通过消息队列发送埋点事件

// 微信公众号:嵌入式大杂烩
struct track_event_common_info *get_track_event_common_info(void)
{
    staticstruct track_event_common_info common_info ={0};
    time_t rawtime;
    struct tm * timeinfo;

    strncpy(common_info.dev_name,"board xxx",sizeof(common_info.dev_name)-1);
    strncpy(common_info.serial_num,"1234ABCD567",sizeof(common_info.serial_num)-1);
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(common_info.timestamp,sizeof(common_info.timestamp),"%Y-%m-%d %H:%M:%S", timeinfo);

    return &common_info;
}

voidsend_event(enum track_event_type event_type, union track_event_info event_info)
{
    struct track_event_common_info *common_info = get_track_event_common_info();
    struct tracking_event event ={0};

    event.event_type = event_type;
    event.event_info = event_info;
    event.event_common_info = common_info;

    if(mq_send(g_mqd,(constchar*)&event,sizeof(event),1)==-1)
    {
        perror("mq_send");
    }
}

5、埋点线程实现

// 微信公众号:嵌入式大杂烩
void*tracking_thread(void *arg)
{
    #define STR(x)  #x 

    FILE*fp = fopen("tracking.log","a");
    if(!fp)
    {
        perror("fopen");
        return NULL;
    }

    struct tracking_event event ={0};
    while(1)
    {
        if(mq_receive(g_mqd,(char*)&event,sizeof(event),NULL)==-1)
        {
            perror("mq_receive");
            continue;
        }

        cJSON *root = cJSON_CreateObject();
        printf("event.event_type = %d\n", event.event_type);
        switch(event.event_type)
        {
            case TRACK_EVENT_TYPE_BOOT:
            {
                cJSON_AddStringToObject(root,"even_type", STR(TRACK_EVENT_TYPE_BOOT));
                cJSON_AddNumberToObject(root,"boot_cnt", event.event_info.track_boot.cnt);
                break;
            }
            case TRACK_EVENT_TYPE_BUTTON:
            {
                cJSON_AddStringToObject(root,"even_type", STR(TRACK_EVENT_TYPE_BUTTON));
                cJSON_AddNumberToObject(root,"button_num", event.event_info.track_button.button_num);
                cJSON_AddNumberToObject(root,"button_type", event.event_info.track_button.button_type);
                break;
            }

            default:
            break;
        }

        cJSON_AddStringToObject(root,"dev_name", event.event_common_info->dev_name);
        cJSON_AddStringToObject(root,"serial_num", event.event_common_info->serial_num);
        cJSON_AddStringToObject(root,"timestamp", event.event_common_info->timestamp);

        char*json_str = cJSON_Print(root);
        fprintf(fp,"%s\n", json_str);
        printf("json_str = %s\n", json_str);
        free(json_str);
        cJSON_Delete(root);

        fflush(fp);

        usleep(100*1000);
    }

    fclose(fp);
    pthread_exit(NULL);
}

6、主函数实现

// 微信公众号:嵌入式大杂烩
intmain(void)
{
    pthread_t thread_id;

    init_mq();

    // 创建跟踪线程  
    if(pthread_create(&thread_id,NULL, tracking_thread,NULL)!=0)
    {
        perror("pthread_create");
        return 1;
    }

    while(1)
    {
        int ch = getchar();
        switch(ch)
        {
            case'1':
            {
                // 模拟发送TRACK_EVENT_TYPE_BOOT事件  
                printf("TRACK_EVENT_TYPE_BOOT\n");
                enum track_event_type event_type ={0};
                union track_event_info event_info ={0};

                event_type = TRACK_EVENT_TYPE_BOOT;
                event_info.track_boot.cnt +=1;
                send_event(event_type, event_info);
                break;
            }
            case'2':
            {
                // 模拟发送button_1_pressed事件  
                printf("TRACK_EVENT_TYPE_BUTTON\n");
                enum track_event_type event_type ={0};
                union track_event_info event_info ={0};

                event_type = TRACK_EVENT_TYPE_BUTTON;
                event_info.track_button.button_num =1;
                event_info.track_button.button_type =1;
                send_event(event_type, event_info);
                break;
            }
            default:
            break;
        }

        usleep(100);
    }

    // 清理  
    pthread_join(thread_id,NULL);
    cleanup_mq();

    return0;
}

编译运行:

gcc cJSON.c test.c -o test -lpthread -lrt

埋点文件把相关埋点事件给记录了下来,实际埋点信息可以根据需要进行增删。

埋点注意事项

  • • 保护用户隐私:确保收集的数据符合隐私政策,避免泄露敏感信息。

  • • 合理控制埋点数量:过多埋点会影响系统性能和用户体验。

  • • 数据准确性:确保收集到的数据准确无误,避免误导决策。

  • • 是否有必要进行埋点?埋点的缺点:

    • • 开发成本高:嵌入式埋点需要在每个监测点都编写单独的事件监测代码,增加了开发工作量。

    • • 存在延迟上报和漏报情况:由于网络延迟、设备性能等因素,可能存在数据上报的延迟或漏报情况。这会影响数据的完整性和准确性。进而会影响数据分析。

    • • 无历史记录:嵌入式埋点只能采集到植入代码之后的数据,无法回溯到之前的历史数据。这可能导致在分析用户行为或系统变化时缺乏全面的数据支持。

    • • 影响系统性能:埋点或多或少会带来一些性能开销。

埋点作为一种数据收集和分析的技术手段,具有其独特的优点和缺点。在实际应用中,需要根据具体需求和场景进行权衡和选择。

猜你喜欢:

Zephyr 会成为物联网时代RTOS的佼佼者?

常用的 Git 提交规范!

嵌入式开发调试利器 | Sanitizer检测器

嵌入式大杂烩 专注于嵌入式技术,包括但不限于C/C++、嵌入式、物联网、Linux等编程学习笔记,同时,内包含大量的学习资源。欢迎关注,一同交流学习,共同进步!
评论
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 120浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 50浏览
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 108浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 98浏览
  • 《高速PCB设计经验规则应用实践》+PCB绘制学习与验证读书首先看目录,我感兴趣的是这一节;作者在书中列举了一条经典规则,然后进行详细分析,通过公式推导图表列举说明了传统的这一规则是受到电容加工特点影响的,在使用了MLCC陶瓷电容后这一条规则已经不再实用了。图书还列举了高速PCB设计需要的专业工具和仿真软件,当然由于篇幅所限,只是介绍了一点点设计步骤;我最感兴趣的部分还是元件布局的经验规则,在这里列举如下:在这里,演示一下,我根据书本知识进行电机驱动的布局:这也算知行合一吧。对于布局书中有一句:
    wuyu2009 2024-11-30 20:30 122浏览
  • 学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&
    youyeye 2024-11-30 14:30 78浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 101浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 71浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 84浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 119浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 68浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 100浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 106浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦