557 lines
22 KiB
C
Executable File

#include <common/sys_config.h>
#include <components/log.h>
#include <modules/wifi.h>
#include <components/netif.h>
#include <components/event.h>
#include <string.h>
#include "bk_private/bk_init.h"
#include <components/system.h>
#include <os/os.h>
#include "components/webclient.h"
#include "cJSON.h"
#include "components/bk_uid.h"
#include "bk_genie_comm.h"
#include "thing.h"
#include "iot_lamp.h"
#include "iot_speaker.h"
#include "iot_sleep_helper.h"
#include "bat_main.h"
#include "application.h"
#include "mcp/mcp_server.h"
#include "beken_rtc.h"
#if (CONFIG_SYS_CPU0)
#include "beken_config.h"
#include "aud_intf.h"
#include "bk_factory_config.h"
#if CONFIG_NETWORK_AUTO_RECONNECT
#include "bk_genie_smart_config.h"
#endif
#endif
#include "iot_lamp.h"
#include "iot_speaker.h"
#include "iot_sleep_helper.h"
#include "bat_main.h"
#include "spi_led.h"
#include "app_event.h"
#include "iot_ota.h"
#include <time.h>
#include "poka_client.h"
#include "mqtt_instance.h"
#include "iot_export_mqtt.h"
#define TAG "APP"
#define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__)
#define LOGW(...) BK_LOGW(TAG, ##__VA_ARGS__)
#define LOGE(...) BK_LOGE(TAG, ##__VA_ARGS__)
#define LOGD(...) BK_LOGD(TAG, ##__VA_ARGS__)
static beken_thread_t app_thread_hdl = NULL;
static beken_thread_t app_mqtt_thread_hdl = NULL;
static app_config_t app_config;
static DeviceState deviceState = kDeviceStateIdle;
app_config_t* app_get_config(){
return &app_config;
}
void app_set_websocket_url(const char* url) {
os_memset(app_config.websocket_url, 0, sizeof(app_config.websocket_url));
os_strcpy(app_config.websocket_url, url);
}
static ReturnValue sleep_helper_set_mode_callback(const PropertyList* properties) {
Property* mode_prop = property_list_get_by_name(properties, "mode");
if (!mode_prop || property_get_type(mode_prop) != PROPERTY_TYPE_INTEGER) {
return return_value_create_string("{\"error\":\"Invalid level parameter\"}");
}
int mode = property_get_integer_value(mode_prop);
sleep_helper_set_mode(mode);
LOGE("sleep_helper_setmode ->%d\n",mode);
return return_value_create_string("{\"success\":true}");
}
static ReturnValue sleep_helper_set_level_callback(const PropertyList* properties) {
Property* level_prop = property_list_get_by_name(properties, "level");
if (!level_prop || property_get_type(level_prop) != PROPERTY_TYPE_INTEGER) {
return return_value_create_string("{\"error\":\"Invalid level parameter\"}");
}
int level = property_get_integer_value(level_prop);
sleep_helper_set_level(level);
LOGE("sleep_helper_set_level ->%d\n",level);
return return_value_create_string("{\"success\":true}");
}
static ReturnValue sleep_helper_open_callback(const PropertyList* properties) {
LOGE("sleep_helper_open_callback\n");
int result = sleep_helper_open();
if(result == -1){
return return_value_create_string("{\"success\":false,\"error\":\"耳夹未接入\"}");
}else{
return return_value_create_string("{\"success\":true}");
}
//return return_value_create_string("{\"success\":true}");
}
static ReturnValue sleep_helper_close_callback(const PropertyList* properties) {
LOGE("sleep_helper_close_callback\n");
sleep_helper_close();
return return_value_create_string("{\"success\":true}");
}
// 设备状态工具回调
static ReturnValue get_device_status_callback(const PropertyList* properties) {
cJSON* status = cJSON_CreateObject();
//软件版本
cJSON* application = cJSON_CreateObject();
cJSON_AddStringToObject(application, "version", APPLICATION_VERSION);
cJSON_AddItemToObject(status, "application", application);
//扬声器状态
cJSON* audio_speaker = cJSON_CreateObject();
cJSON_AddNumberToObject(audio_speaker, "volume", speaker_volume_get_current());
cJSON_AddItemToObject(status, "audio_speaker", audio_speaker);
//灯光状态 不需要获取 肉眼所见
cJSON* light = cJSON_CreateObject();
cJSON_AddNumberToObject(light, "brightness", lamp_get_bright());
//cJSON_AddStringToObject(screen, "theme", "light");
cJSON_AddItemToObject(status, "light", light);
//电池状态
cJSON* battery = cJSON_CreateObject();
cJSON_AddNumberToObject(battery, "level", battery_get_percent());
cJSON_AddItemToObject(status, "battery", battery);
char *jsonString = cJSON_PrintUnformatted(status);
ReturnValue ret = return_value_create_string(jsonString);
cJSON_Delete(status);
return ret;
}
// 设置音量工具回调
static ReturnValue set_volume_callback(const PropertyList* properties) {
Property* volume_prop = property_list_get_by_name(properties, "volume");
if (!volume_prop || property_get_type(volume_prop) != PROPERTY_TYPE_INTEGER) {
return return_value_create_string("{\"error\":\"Invalid volume parameter\"}");
}
int volume = property_get_integer_value(volume_prop);
LOGE("board_set_volume ->%d\n",volume);
//board_set_volume(volume);
//uint32_t speaker_volume_get_current();
speaker_set_volume(volume);
return return_value_create_string("{\"success\":true}");
}
// 设置亮度工具回调
static ReturnValue set_brightness_callback(const PropertyList* properties) {
Property* brightness_prop = property_list_get_by_name(properties, "brightness");
if (!brightness_prop || property_get_type(brightness_prop) != PROPERTY_TYPE_INTEGER) {
return return_value_create_string("{\"error\":\"Invalid brightness parameter\"}");
}
int brightness = property_get_integer_value(brightness_prop);
if(brightness == 0){
ws2812_led_clear_all();
}else{
//ws2812_set_all_led(0xFFFFFF,brightness);
ws2812_set_all_led_brightness(brightness);
}
LOGE("board_set_brightness ->%d\n",brightness);
return return_value_create_string("{\"success\":true}");
}
// 设置主题工具回调
static ReturnValue set_theme_callback(const PropertyList* properties) {
Property* theme_prop = property_list_get_by_name(properties, "theme");
if (!theme_prop || property_get_type(theme_prop) != PROPERTY_TYPE_STRING) {
return return_value_create_string("{\"error\":\"Invalid theme parameter\"}");
}
const char* theme = property_get_string_value(theme_prop);
LOGE("board_set_theme ->%s\n",theme);
return return_value_create_string("{\"success\":true}");
}
// 拍照工具回调
static ReturnValue take_photo_callback(const PropertyList* properties) {
ReturnValue ret = return_value_create_string("photo_data");
return ret;
}
// OTA升级检测工具回调
static ReturnValue ota_update_device_callback(const PropertyList* properties) {
// ReturnValue ret = return_value_create_string("photo_data");
// 电量低于25 不允许执行OTA
int battery = battery_get_percent();
if (battery < 25)
{
LOGE("power low bat:%d ,don't ota !!\n", battery);
app_event_send_msg(APP_EVT_LOW_VOLTAGE, 0);
return return_value_create_string("{\"success\":false,\"error\":\"电量低,不允许升级设备\"}");
}
iot_lamp_check_ota();
return return_value_create_string("{\"success\":true}");
}
// 设备助眠仪状态回调
static ReturnValue sleep_helper_get_device_status_callback(const PropertyList* properties) {
cJSON* status = cJSON_CreateObject();
//助眠仪的状态
cJSON* sleep_helper = cJSON_CreateObject();
cJSON_AddNumberToObject(sleep_helper, "model", sleep_helper_get_mode());
cJSON_AddNumberToObject(sleep_helper, "level", sleep_helper_get_level());
cJSON_AddItemToObject(status, "sleep_helper", sleep_helper);
char *jsonString = cJSON_PrintUnformatted(status);
ReturnValue ret = return_value_create_string(jsonString);
cJSON_Delete(status);
return ret;
}
// 获取体温数据回调
static ReturnValue health_get_temperature_callback(const PropertyList* properties) {
#if 0
cJSON* status = cJSON_CreateObject();
cJSON* health = cJSON_CreateObject();
cJSON_AddNumberToObject(health, "body_temperature", 38.5);
cJSON_AddItemToObject(status, "health", health);
char *jsonString = cJSON_PrintUnformatted(status);
ReturnValue ret = return_value_create_string(jsonString);
cJSON_Delete(status);
return ret;
#endif
return return_value_create_string("{\"success\":false,\"error\":\"获取体温功能正在完善,敬请期待\"}");
}
// 获取血压数据回调
static ReturnValue health_get_bloodpressure_callback(const PropertyList* properties) {
#if 0
cJSON* status = cJSON_CreateObject();
cJSON* health = cJSON_CreateObject();
cJSON_AddNumberToObject(health, "bloodpressure", 120);
cJSON_AddItemToObject(status, "health", health);
char *jsonString = cJSON_PrintUnformatted(status);
ReturnValue ret = return_value_create_string(jsonString);
cJSON_Delete(status);
return ret;
#endif
return return_value_create_string("{\"success\":false,\"error\":\"获取血压功能正在完善,敬请期待\"}");
}
static ReturnValue health_analysis_report_callback(const PropertyList* properties) {
#if 0
cJSON* status = cJSON_CreateObject();
cJSON* health = cJSON_CreateObject();
cJSON_AddNumberToObject(health, "bloodpressure", 120);
cJSON_AddItemToObject(status, "health", health);
char *jsonString = cJSON_PrintUnformatted(status);
ReturnValue ret = return_value_create_string(jsonString);
cJSON_Delete(status);
return ret;
#endif
return return_value_create_string("{\"success\":false,\"error\":\"分析健康报告功能正在完善,敬请期待\"}");
}
static ReturnValue wifi_get_signal_report_callback(const PropertyList* properties) {
int err = kNoErr;
wifi_link_status_t link_status = {0};
os_memset(&link_status, 0x0, sizeof(link_status));
err = bk_wifi_sta_get_link_status(&link_status);
if (err != kNoErr)
{
return return_value_create_string("{\"success\":false,\"error\":\"获取wifi状态失败\"}");
}
LOGE("RSSI:%d\n", link_status.rssi);
if(link_status.rssi >= -50 ){
return return_value_create_string("{\"success\":false,\"error\":\"信号强度非常好\"}");
}else if (link_status.rssi >= -60){
return return_value_create_string("{\"success\":false,\"error\":\"信号强度良好\"}");
}else if (link_status.rssi >= -70){
return return_value_create_string("{\"success\":false,\"error\":\"信号强度一般\"}");
}else if (link_status.rssi >= -75){
return return_value_create_string("{\"success\":false,\"error\":\"信号强度较差\"}");
}else{
return return_value_create_string("{\"success\":false,\"error\":\"信号强度很差\"}");
}
}
void app_mcp_init(){
McpServer* mcp_server = mcp_server_get_instance();
// 助眠仪模式
{
PropertyList* props = property_list_create();
Property* prop_mode = property_create_integer("mode", false, 0, true, 0, 3);
property_list_add_property(props, prop_mode);
mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.set_mode", "设置助眠仪的模式", props, sleep_helper_set_mode_callback);
}
// 助眠仪等级
{
PropertyList* props = property_list_create();
Property* prop_level = property_create_integer("level", false, 1, true, 1, 9);
property_list_add_property(props, prop_level);
mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.set_level", "设置助眠仪的等级", props, sleep_helper_set_level_callback);
}
//打开助眠仪
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.open", "打开助眠仪", props, sleep_helper_open_callback);
}
//关闭助眠仪
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.close", "关闭助眠仪", props, sleep_helper_close_callback);
}
// 获取助眠仪状态
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.get_status",
"获取助眠仪状态 (mode=0 表示已经关闭, mode=1 表示模式1, mode=2 表示模式2,mode=3 表示模式3,level (0-9)分别代表9个不同等级", props, sleep_helper_get_device_status_callback);
}
// 添加获取设备状态工具
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.get_device_status", "获取软件版本,设备音量,灯光亮度,设备电池状态", props, get_device_status_callback);
}
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.wifi.get_signal", "获取设备网络信号强度", props, wifi_get_signal_report_callback);
}
// 添加设置音量工具
{
PropertyList* props = property_list_create();
Property* volume_prop = property_create_integer("volume", false, 0, true, 0, 100);
property_list_add_property(props, volume_prop);
//Property* vol_prop = property_create_integer("vol", false, 0, true, 0, 100);
//property_list_add_property(props, vol_prop);
mcp_server_add_tool_with_params(
mcp_server,
"self.audio_speaker.set_volume",
"Set the volume of the audio speaker. If the current volume is unknown, you must call `self.get_device_status` tool first and then call this tool.",
props, set_volume_callback);
}
// 添加设置亮度工具
{
PropertyList* props = property_list_create();
Property* brightness_prop = property_create_integer("brightness", false, 0, true, 0, 100);
property_list_add_property(props, brightness_prop);
mcp_server_add_tool_with_params(mcp_server, "self.light.set_brightness", "设置拍拍灯的灯光亮度", props, set_brightness_callback);
}
// 添加拍照工具
//{
// PropertyList* props = property_list_create();
// mcp_server_add_tool_with_params(mcp_server, "take_photo", "Take a photo", props, take_photo_callback);
//}
// OTA
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.ota.update_device", "更新拍拍灯乐小牛软件,执行该指令需要和用户二次确认才允许下发这个指令,并提示大约等待3分钟后手动重启设备", props, ota_update_device_callback);
}
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.health.get_temperature", "获取用户最近温度数据", props, health_get_temperature_callback);
}
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.health.get_bloodpressure", "获取用户最近血压数据", props, health_get_bloodpressure_callback);
}
{
PropertyList* props = property_list_create();
mcp_server_add_tool_with_params(mcp_server, "self.health.analysis_report", "获取用户最近健康分析报告", props, health_analysis_report_callback);
}
}
void app_set_device_state(DeviceState state){
deviceState = state;
switch(deviceState){
case kDeviceStateIdle:
LOGE("set_device_state -> idle\n");
break;
case kDeviceStateConnecting:
LOGE("set_device_state -> connecting\n");
break;
case kDeviceStateListening:
LOGE("set_device_state -> listening\n");
break;
case kDeviceStateSpeaking:
LOGE("set_device_state -> speaking\n");
break;
case kDeviceStateUpgrading:
LOGE("set_device_state -> upgrading\n");
break;
case kDeviceStateActivating:
LOGE("set_device_state -> activating\n");
break;
case kDeviceStateAudioTesting:
break;
default:
break;
}
}
void app_on_incoming_json(char *json_text, unsigned int size){
}
DeviceState app_get_device_state(){
return deviceState;
}
void app_ota_check(){
LOGE("app_ota_check\n");
if (!ota_has_websocket_config())
{
// 读取OTA地址
char ota_url[128] = {0};
memset(ota_url, 0, sizeof(ota_url));
int ret_size = bk_config_read("ai_ota_url", (void *)&ota_url, sizeof(ota_url));
// 判断是否是合法http地址
if (ret_size > 0 && NULL != strstr((char *)ota_url, "http"))
{
LOGE("bk_config_read ai_ota_url (%d) :%s\n", ret_size, ota_url);
LOGE("bk_config_read ai_ota_url strlen (%d) \n", strlen(ota_url));
}
else
{
LOGE("bk_config_read ai_ota_url fail,use defult\n");
memset(ota_url, 0, sizeof(ota_url));
sprintf(ota_url, "%s", APPLICATION_DEFULT_OTA_URL);
}
// 检测OTA 并且通过OTA 获取WEBSOCKET地址
int check_version = ota_check_version(ota_url);
if (check_version == BK_OK)
{
LOGE("check_version %d\n", check_version);
LOGE("ota_has_activation_code %d\n", ota_has_activation_code());
LOGE("ota_has_websocket_config %d\n", ota_has_websocket_config());
if (ota_has_activation_code())
{
// 激活设备
ota_register_device();
}
if (ota_has_websocket_config())
{
extern bk_err_t beken_rtc_start(void);
beken_rtc_start();
}
}
}else{
extern bk_err_t beken_rtc_start(void);
beken_rtc_start();
}
}
void app_ai_agent_start(){
bk_err_t ret = BK_OK;
ret = rtos_create_thread(&app_thread_hdl,
4,
"OTA_CHECK",
(beken_thread_function_t)app_ota_check,
35 * 1024,
NULL);
if (ret != kNoErr)
{
app_thread_hdl = NULL;
}
}
//物联网平台相关回调函数
void funs_exec_action_callback(int duration,char *hint_text,int action){
BK_LOGE(TAG,"funs_exec_action_callback \r\n");
}
void funs_play_text_callback(char * text,int repeat_count){
BK_LOGE(TAG,"funs_play_text_callback \r\n");
//帮我读一下以下内容:text
cJSON *json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "type", "listen");
cJSON_AddStringToObject(json, "state", "detect");
char tts_text[256] = {0};
sprintf(tts_text, "帮我朗读内容:%s", text);
cJSON_AddStringToObject(json, "text", tts_text);
cJSON_AddStringToObject(json, "source", "text");
mcp_send_mcp_message(cJSON_PrintUnformatted(json));
cJSON_Delete(json);
}
static int is_first_mqtt_connected = 0;
void event_link_state_callback(int state){
BK_LOGE(TAG,"event_link_state_callback:%d\r\n", state);
if(state == MQTT_INSTANCE_EVENT_CONNECTED){
if(!is_first_mqtt_connected){
is_first_mqtt_connected = 1;
//连接成功时
//poka_client_reply_properties("1234567890");
//设备MAC
uint8_t base_mac[BK_MAC_ADDR_LEN] = {0};
bk_get_mac(base_mac, MAC_TYPE_BASE);
char mac_str[32] = {0};
sprintf(mac_str,"%02X%02X%02X%02X%02X%02X",base_mac[0], base_mac[1], base_mac[2], base_mac[3], base_mac[4], base_mac[5]);
//设备名称
char device_name [12] = {0};
sprintf(device_name, "iR58_%02X%02X",base_mac[4], base_mac[5]);
poka_client_report_device_tags(APPLICATION_VERSION,mac_str,mac_str,device_name,APPLICATION_HARDWARE_VERSION);
int device_volme = speaker_volume_get_current();
int device_bright = lamp_get_bright();
int sleep_mode = sleep_helper_get_mode();
int sleep_level = sleep_helper_get_level();
//int sleep_work_time = sleep_helper_get_work_timeout();
int battery_p = battery_get_percent();
int bright_close_timeout = ws2812_get_work_timeout();
int bright_open = ws2812_is_bright();
int charging = 1;
int network_state = 1;
poka_client_report_properties(battery_p,charging,network_state,network_state,device_volme,bright_open,device_bright,
bright_close_timeout,sleep_mode>0?1:0,sleep_mode,sleep_level );
}
}else if(state == MQTT_INSTANCE_EVENT_DISCONNECTED){
//连接断开时
}
}
static poka_client_cb_ops_t cloud_event_ops = {
.funs_exec_action = funs_exec_action_callback,
.funs_play_text = funs_play_text_callback,
.event_link_state = event_link_state_callback,
};
void app_mqtt_thread(){
BK_LOGE(TAG,"app_mqtt_start \r\n");
poka_client_set_callback(&cloud_event_ops);
poka_client_init();
}
void app_mqtt_start(){
//init poka cloud plat
bk_err_t ret = BK_OK;
ret = rtos_create_thread(&app_mqtt_thread_hdl,
4,
"POKA_MQTT",
(beken_thread_function_t)app_mqtt_thread,
20 * 1024,
NULL);
if (ret != kNoErr)
{
app_mqtt_thread_hdl = NULL;
}
}
void app_start(){
app_mcp_init();
//app_ai_init();
}