$(BUILD)/motor.mpy \
$(BUILD)/ai_VC.mpy \
$(BUILD)/ui_setting.mpy \
+ $(BUILD)/ai_alarm.mpy \
endif
import dataCall
import constants
import versions
+import usocket
+import lvgl as lv
try:
import VAD
except Exception as e:
usys.print_exception(e)
+try:
+ import usr.ai_alarm as _ai_alarm
+except Exception as e:
+ usys.print_exception(e)
+ import ai_alarm as _ai_alarm
#dev_type = "G10"
#dev_type = "7PIN_BK"#小瑞
#dev_type = "7PIN_BK_coze"#k扣子小瑞
EventMesh.subscribe("paly_iccid_imei",self.paly_iccid_imei)
EventMesh.subscribe("paly_device_res_error",self.paly_device_res_error)
EventMesh.subscribe("Power_off",self.pwk_key_Long_Press)
+ EventMesh.subscribe("get_usb_status",self.get_usb_status)
print("AI_dev:2")
self.pk = PowerKey()
self.Low_power_warning_flag = 0
self.VC_TTS_volume = EventMesh.publish("get_storage_config","VC_TTS_volume")#音量配置
if self.VC_TTS_volume == None:
- self.VC_TTS_volume = 110
- self.aud.setVolume(self.VC_TTS_volume // 10)
- print("音量初始化DEV配置为{}".format(self.VC_TTS_volume // 10))
+ self.VC_TTS_volume = 100
+ self.aud.setVolume(self.VC_TTS_volume //10)
#self.aud.play(1,0,'U:/static/xianyikaiji.mp3')#开机音频
#EventMesh.publish("audio_montage_play",["xianyikaiji.mp3"])
#EventMesh.publish("publish_AI_btnInfo",{"func":self.ntptime_cb})
#双击逻辑
self.last_time = 0 #上次时间
- self.gap_time = 2000 #双击间隔时间(ms)
+ self.gap_time = 1500 #双击间隔时间(ms)
self.double_flag = 0 #双击标志
self.double_release_timer = osTimer()#双击释放定时器
print("AI_dev:end")
print("timer:{}!!!!!!!!\r\n".format(utime.localtime()))
def usb_event_cb(self, state):
EventMesh.publish("publish_AI_btnInfo",{"func":self.usb_event,"data":state})
-
+ def get_usb_status(self,event= None,msg = None):
+ return self.usb_status
def usb_event(self, state):
status = state
self.usb_charge_flag = 0
print("charge R_CHARGE_in")
self.usb_status = 1
VC_satrt_flag = EventMesh.publish("get_VC_satrt_flag")#获取vc是否在运行
+ EventMesh.publish("send_device_information")#发送设备信息
if VC_satrt_flag == None:
VC_satrt_flag = 0
if VC_satrt_flag == 0:
elif status == 0:#拨出usbs
self.usb_status = 0
VC_satrt_flag = EventMesh.publish("get_VC_satrt_flag")#获取vc是否在运行
+ EventMesh.publish("send_device_information")#发送设备信息
if VC_satrt_flag == None:
VC_satrt_flag = 0
if VC_satrt_flag == 0:
self.KeyAI_timer_count = 0
EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_double_press})
# 启动双击释放检测计时器
- self.double_release_timer.start(500, 1, self.double_release_timeout)
+ self.double_release_timer.start(500, 0, self.double_release_timeout)
return
-
- EventMesh.publish(constants.EVENT.SYSTEM_UP)#唤醒休眠
- self.extint_AI.disable()
- self.KeyAI_press = 1
- self.KeyAI_long_press = 0
- self.KeyAI_timer.start(100, 1, self.KeyAI_timer_cb)
- self.KeyAI_timer_count = 0
- #EventMesh.publish("AI_key_press")
- if dev_type == "7PIN" or dev_type == "7PIN_coze" :
- self.aud.aud_tone_play(10,200)#播放按键音
- EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_press})
- self.last_time = current_time
+ elif time_tiff > 0 and current_time - self.last_time > self.gap_time:#判断为单击
+ EventMesh.publish(constants.EVENT.SYSTEM_UP)#唤醒休眠
+ self.extint_AI.disable()
+ self.KeyAI_press = 1
+ self.KeyAI_long_press = 0
+ self.double_flag = 0
+ self.KeyAI_timer.start(100, 1, self.KeyAI_timer_cb)
+ self.KeyAI_timer_count = 0
+ #EventMesh.publish("AI_key_press")
+ screen_name = EventMesh.publish("get_screen_NAME")
+ if screen_name != "system_init" and screen_name != "poweron":
+ if dev_type == "7PIN" or dev_type == "7PIN_coze" :
+ self.aud.aud_tone_play(10,200)#播放按键音
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_press})
+ self.last_time = current_time
else: # 释放
if self.double_flag:
# 双击释放处理
self.KeyAI_timer_count = 0
self.KeyAI_press = 0
return
+
except Exception as e:
usys.print_exception(e)
def double_release_timeout(self, *args, **kwargs):#双击释放超时处理
+ print("定时器未关闭!!!!!!!!")
if self.double_flag:
#如果超时仍未释放,重置双击状态
self.double_flag = 0
+ self.double_release_timer.stop()
def AI_key_double_release(self):
EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_double_press})
try:
self.KeyAI_status = self.extint_AI.read_level()
self.KeyAI_timer_count +=1
- print("self.KeyAI_timer_count = {}".format(self.KeyAI_timer_count))
+ # print("self.KeyAI_timer_count = {}".format(self.KeyAI_timer_count))
if self.KeyAI_timer_count >= 10*1 : #长按1s
if self.KeyAI_long_press == 0:
self.KeyAI_long_press = 1
self.KeyAI_timer.stop()
self.KeyAI_timer_count = 0
self.KeyAI_press = 0
- # current_time = utime.ticks_ms()
- # print("current_time:{},last_time:{},current_time - self.last_time={}".format(current_time,self.last_time,current_time - self.last_time))
- # if (current_time - self.last_time <= self.gap_time):#鉴定为双击
- # print("AI_key_double_press DOUBLE DOUBLE ")
- # self.double_flag = 1#切换标志位
- # self.KeyAI_long_press = 0
- # self.KeyAI_press = 0
- # self.KeyAI_timer_count = 0
- # EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_double_press})
- # return
- # else:
- # EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_key_press})
- # self.KeyAI_press = 1
- # self.KeyAI_long_press = 0
- # self.KeyAI_timer_count = 0
-
- # self.last_time = current_time
except Exception as e:
usys.print_exception(e)
self.check_rest_timer_count = 0
print("pwk_key_long_press!!!!!!!")
print("pwk_key_long_press!!!!!!!")
+ EventMesh.publish_async("audio_montage_play",["zhengzaiguanji.mp3"])
EventMesh.publish("load_screen", {"screen": "poweroff_comfirm"})#关机画面
# EventMesh.publish("paly_iccid_imei")
# return
- EventMesh.publish_async("audio_montage_play",["zhengzaiguanji.mp3"])
#self.aud.play(1,0,'U:/static/zhengzaiguanji.mp3')#关机音频
EventMesh.publish("open_led_red")
- utime.sleep_ms(3000)
+ utime.sleep_ms(4000)
self.aud.stopPlayStream()
self.aud.stopAll()
Power.powerDown()
VC_satrt_flag = 0
Vbatt = Power.getVbatt()
if self.usb_status == 1 and VC_satrt_flag == 0:
- EventMesh.publish("open_led_red")#充电红灯常亮
+ #EventMesh.publish("open_led_red")#充电红灯常亮
+ pass
if self.usb_status == 1 and Vbatt>=self.VBATT_tab["charge_full"]and VC_satrt_flag == 0:#充电充满
- EventMesh.publish("open_led_green")
+ #EventMesh.publish("open_led_green")
if self.usb_charge_flag == 0 :
- EventMesh.publish("audio_montage_play",["R_CHARGE_FULL.mp3"])
- EventMesh.publish("load_screen", {"screen": "charge_full"})#满电弹窗
- #self.aud.play(1,0,'U:/static/R_CHARGE_FULL.mp3')#充电已满
- # EventMesh.publish("load_screen", {"screen": "charge_full"})#充满电弹窗
- self.usb_charge_flag = 1
- if self.usb_status == 0 and Vbatt<self.VBATT_tab["20"]and VC_satrt_flag == 0 and self.Low_power_warning_flag ==0:#低电报警
+ screen_name = EventMesh.publish("get_screen_NAME")
+ if screen_name != "system_init" and screen_name != "poweron" and screen_name != "UI_ai":
+ EventMesh.publish("audio_montage_play",["R_CHARGE_FULL.mp3"])
+ EventMesh.publish("load_screen", {"screen": "charge_full"})#满电弹窗
+ #self.aud.play(1,0,'U:/static/R_CHARGE_FULL.mp3')#充电已满
+ # EventMesh.publish("load_screen", {"screen": "charge_full"})#充满电弹窗
+ self.usb_charge_flag = 1
+ if self.usb_status == 0 and Vbatt<self.VBATT_tab["40"]and VC_satrt_flag == 0 and self.Low_power_warning_flag ==0:#低电报警
self.Low_power_warning_flag = 1
- EventMesh.publish("flicker_led_red")
+ # EventMesh.publish("flicker_led_red")
+ #utime.sleep_ms(150)
+ if screen_name != "system_init" and screen_name != "poweron" :
+ EventMesh.publish("load_screen", {"screen": "LOW_POWER"})#少电弹窗
+ EventMesh.publish("audio_montage_play",["Low_power_warning.mp3"])
#self.aud.play(1,0,'Low_power_warning.mp3')
# self.Low_power_warning_timer+=1
# if self.Low_power_warning_timer >= 2:
# self.Low_power_warning_timer = 0
- EventMesh.publish("audio_montage_play",["Low_power_warning.mp3"])
+
if self.usb_status == 0 and Vbatt>=self.VBATT_tab["20"]and VC_satrt_flag == 0:#没有充电,电量又正常,关灯
EventMesh.publish("close_led")
#7pin
self.key = b"uKLrChwrxA1LklgBc3VwawYjUkbT3BgX"
self.pid = "cqxJZi5CNgzjS3mX21Zw"
+
# if dev_type == 'jswm' or dev_type == 'jswm_BOX':#金三完美
# self.key = b"FuXG4ptpGbzvKbdB4vpUypisbENgy2nB"
# self.pid = "DieBeXahZHLrjSnORbgN"
EventMesh.subscribe("dev_active", self.dev_active)
EventMesh.subscribe("dev_sign_in", self.dev_sign_in)
EventMesh.subscribe("dev_NTP", self.dev_NTP)
+ EventMesh.subscribe("iccid_get", self.iccid_get)
+ EventMesh.subscribe("post_iccid", self.post_iccid)
#EventMesh.publish_async("dev_NTP",thread_size = 8192)
# count = 0
# break
# EventMesh.publish_async("dev_active",thread_size = 8192)
# EventMesh.publish_async("dev_sign_in",thread_size = 8192)
-
self.dev_NTP()#获取时间
self.dev_active() #设备激活
self.dev_sign_in() #设备登入
+ self.post_iccid()#上报iccid
+ self.iccid_get()#自动充值
print("device_res_author __init__ end !!!!!!!!!!!!!!!!!")
def get_dev_token(self, event, msg):
return self.dev_token
+ #上报iccid
+ def post_iccid(self, event=None, msg=None):
+ print("post_iccid")
+ deviceId = self.deviceId
+ url = "https://dmp-dev.raisound.com/dmp-api/dev/iccid"
+ token = self.dev_token
+ if token == None:
+ token = ""
+ iccid = sim.getIccid()
+ headers_T = {"bz-dt":"{}".format(token),"Content-Type":"application/x-www-form-urlencoded"}
+ data = "deviceId={}&iccid={}".format(deviceId,iccid)
+ print(ujson.dumps(data))
+ response = request.post(url,data=data,headers = headers_T,timeout=5)
+ data = response.json()
+ print("iccid_post:{}".format(data))
+ print("end_post_iccid")
+
+ #自动充值
+ def iccid_get(self, event=None, msg=None):
+ print("iccid_get")
+ url = "https://dmp-dev.raisound.com/dmp-api/sv/iccid/charge-task?deviceId={}".format(self.deviceId)
+ token = self.dev_token
+ if token == None:
+ token = ""
+ headers_T = {"bz-dt":"{}".format(token),"Content-Type":"application/x-www-form-urlencoded"}
+ print("bz-dt:{}".format(token))
+ response = request.get(url,headers = headers_T,timeout=5)
+ data = response.json()
+ print("iccid_get:{}".format(data))
+ print("end_iccid_get")
+
#网络校时
def dev_NTP(self, event=None, msg=None):
response = None
if dev_type == "7PIN_BK_EU":#英文小瑞
url = "http://dmp-global.raisound.com/bz-api/dev/time"
else:
+ # url = "http://dmp-dev.raisound.com/dmp-api/dev/time"
url = "http://dmp.raisound.com/bz-api/dev/time"
response = request.get(url,timeout=5)
data = response.json()
print("timer:{}!!!!!!!!\r\n".format(utime.localtime()))
EventMesh.publish_async("dev_active",thread_size = 8192)
EventMesh.publish_async("dev_sign_in",thread_size = 8192)
+ EventMesh.publish_async("post_iccid",thread_size = 8192)
+ EventMesh.publish_async("iccid_get",thread_size = 8192)
# self.dev_active() #设备激活
# self.dev_sign_in() #设备登入
self.dev_res_timerCount+=1
if dev_type == "7PIN_BK_EU":#英文小瑞
url = "http://dmp-global.raisound.com/bz-api/dev/auth/active"
else:
+ # url = "http://dmp-dev.raisound.com/dmp-api/dev/auth/active"
url = "http://dmp.raisound.com/bz-api/dev/auth/active"
data =ujson.dumps(data)
response = None
if dev_type == "7PIN_BK_EU":#英文小瑞
sign_url = "http://dmp-global.raisound.com/bz-api/dev/auth/sign_in" #登入地址
else:
+ # sign_url = "http://dmp-dev.raisound.com/dmp-api/dev/auth/sign_in"
sign_url = "http://dmp.raisound.com/bz-api/dev/auth/sign_in" #登入地址
headers_T ={"Content-Type":"application/json"}
response_result = 0
if dev_type == "7PIN_BK_EU":#英文小瑞
dev_tokenip = "http://dmp-global.raisound.com/bz-api/dev/auth/token" #设备新令牌更新地址
else:
+ # dev_tokenip = "http://dmp-dev.raisound.com/dmp-api/dev/auth/token"
dev_tokenip = "http://dmp.raisound.com/bz-api/dev/auth/token" #设备新令牌更新地址
token = self.dev_token
if token == None:
except Exception as e:
usys.print_exception(e)
print("update_dev_token end")
-
+
#OTA升级
class OTA():
def __init__(self):
self.downloadFileVoURL2= ""
try:
sourceVersion = versions.Build_Time
- sourceVersion = "7PIN-"+sourceVersion[:10]+"-"+sourceVersion[11:-3]
+ sourceVersion = "JSWM-"+sourceVersion[:10]+"-"+sourceVersion[11:-3]
print("sourceVersion:{}".format(sourceVersion))
sourceVersion = sourceVersion.replace(" ", "0")
print("sourceVersion2:{}".format(sourceVersion))
response = None
try:
currentVersion = versions.Build_Time
- currentVersion = "7PIN-"+currentVersion[:10]+"-"+currentVersion[11:-3]
+ currentVersion = "JSWM-"+currentVersion[:10]+"-"+currentVersion[11:-3]
print("currentVersion1:{}".format(currentVersion))
currentVersion = currentVersion.replace(" ", "0")
print("currentVersion2:{}".format(currentVersion))
url =None
if dev_type == "7PIN_BK_EU":#英文小瑞
url = "http://dmp-global.raisound.com/bz-api/dev/iccid?deviceId={}&iccid={}".format(modem.getDevImei(),iccid)
- else:
+ else:
url = "http://dmp.raisound.com/bz-api/dev/iccid?deviceId={}&iccid={}".format(modem.getDevImei(),iccid)
print("{} H:{}".format(url,headers_T))
response = request.post(url,headers = headers_T,timeout=5)
AI_client_VC_num = 3
AI_client_asr_num = 4
-
class AI_VC(Abstract):
# AI
self.VC_30S_timer = osTimer()
self.VC_30S_timer.start(30000, 1, self.VC_30S_timer_cb)
self.get_config_timer_count = 0
+ self.send_timer_count = 0
self.record_data_save_flag = 0 #是否保存录音文件
self.play_data_save_flag = 0#是否保存tts数据到文件
self.record_fd = None
self.VC_mode = 0
self.is_up_error= 0 #是否上传错误id
self.Close_flag =0 #=1时,连续对话播放完音频就退出
-
+ self.AI_alarm = _ai_alarm.AI_alarm()
+
+ #表情变化状态以及检索词
+ self.face_status = 0 # 0为正常,1为哭泣,2为愤怒,3为疑惑
+ self.normal_list = ["别生气"]
+ self.cry_list = ["委屈","难过","伤","哭","泪","颤抖","湿润","泛红","惊慌","担忧","失落","对不起","打扰"]
+ self.angry_list = ["怒","生气","不耐烦"]
+ self.confused_list = ["疑惑","困惑","好奇"]
+
self.error_data = []
self.asr_taskid = ""
self.VC_taskid = ""
self.VC_server = 2 #0柒牌正式服务器,1:测试服务器1,2:测试服务器2
+
self.server_ip = EventMesh.publish("get_storage_config","server_ip")#
if self.server_ip == None:
if self.VC_server == 1:#
elif self.VC_server == 8:#
self.server_ip="115.190.94.208:22080"
elif self.VC_server == 86:#
- self.server_ip="118.145.158.207:22086"
+ self.server_ip="118.145.158.207:22086"
+ # self.server_ip="118.145.158.207:22080"
else:
#self.server_ip="sevenpin.qipai.com.cn"
self.server_ip="118.145.158.207:22082"
if dev_type == 'jswm' or dev_type == 'jswm_BOX':#
#self.server_ip="115.190.94.208:22080"
- self.server_ip="118.145.158.207:22086"
+ # self.server_ip="118.145.158.207:22086"
+ self.server_ip="118.145.158.207:22080"
elif dev_type == "7PIN" or dev_type == "7PIN_coze":
#self.server_ip="sevenpin.qipai.com.cn"
# self.server_ip="220.160.104.34"
except Exception as e:
usys.print_exception(e)
#配置词
- self.commands_mode = 2 #=1用大模型判断命令,=0用服务器本地插件判断命令 =2用设备本地判断方式
+ self.commands_mode = 1 #=1用大模型判断命令,=0用服务器本地插件判断命令 =2用设备本地判断方式
if dev_type == "7PIN_BK"or dev_type == "7PIN_BK_EU"or dev_type == "7PIN_BK_coze":
self.commands_mode = 2
self.commands = [
self.AI_audio_queue = Queue(100)
#self.AI_WS_connect_Queue = Queue(100) #释放用
self.AI_TTS_str = ""
+ self.AI_music_str = ""
self.AI_ASR_str = ""
self.AI_ASR_flag = 0
self.AI_ASR_str_tmp = ""
self.AI_ASR_check_timeout = 0
self.AI_ASR_error_timeout = 0
self.VC_Thinking_timerout = 0
+
self.record_pcm = None
self.play_pcm = None
self.tts_out_data_len = 0
self.VC_satrt_flag = 0
self.session_id = ""
+
+ self.draw_result = 0#抽签结果
EventMesh.subscribe("AI_key_press", self.AI_key_press)
EventMesh.subscribe("AI_key_double_press", self.AI_key_double_press)
EventMesh.subscribe("AI_key_release", self.AI_key_release)
EventMesh.subscribe("get_VC_satrt_flag", self.get_VC_satrt_flag)
EventMesh.subscribe("VC_error", self.VC_error)
EventMesh.subscribe("screen_get_ai", self.screen_get_ai)
+ EventMesh.subscribe("screen_get_draw", self.screen_get_draw)
+ EventMesh.subscribe("screen_get_face", self.screen_get_face)
+ EventMesh.subscribe("play_tts", self.play_tts)
+ EventMesh.subscribe("play_tts_open", self.play_tts_open)
+ EventMesh.subscribe("play_tts_single", self.play_tts_single)
+ EventMesh.subscribe("draw_handle", self.draw_handle)
+ EventMesh.subscribe("dmp_update", self.dmp_update)
+ EventMesh.subscribe("update_volume", self.update_volume)
EventMesh.publish("close_led")
self.bot_name = "柒先生"
#EventMesh.publish("get_storage_config",["powerRestart",1])
+ self.aud.play(1, 1, 'E:/static/R_POWER_1.mp3') #播放播放开机铃声
powerRestart = EventMesh.publish("get_storage_config","powerRestart")#=1非正常重启
if powerRestart == None:
powerRestart = 0
return self.VC_satrt_flag
def screen_get_ai(self, event=None, msg=None):
return self.VC_state
+ def screen_get_draw(self, event=None, msg=None):
+ return self.draw_result
+ def screen_get_face(self, event=None, msg=None):
+ return self.face_status
+ def create_ordered_json(self,device_id, server_ip, signalLevel, battery):
+ # 按预期顺序手动拼接JSON字符串
+ # 外层结构:先path,后Body
+ json_str = "{"
+ # 1. 拼接path部分(固定顺序)
+ json_str += '"path": {{"deviceId": "{}"}},'.format(device_id)
+ # 2. 拼接Body部分(按需求顺序排列)
+ json_str += '"Body": {'
+ json_str += '"wifiName": "",'
+ json_str += '"ipAddr": "{}",'.format(server_ip)
+ json_str += '"dnsAddr": "8.8.8.8",'
+ json_str += '"gateWayAddr": "192.168.0.1",'
+ json_str += '"signalLevel": "{}",'.format(signalLevel)
+ json_str += '"battery": "{}"'.format(battery)
+ json_str += "}"
+ # 闭合外层
+ json_str += "}"
+ return json_str
+
+ def dmp_update(self, event=None, msg=None):
+ device_id = modem.getDevImei()
+ signalLevel = str(net.csqQueryPoll()*3) + "%"
+ battery = str((EventMesh.publish("screen_get_battery"))[1]) + "%"
+ datacall = dataCall.getInfo(1, 0)
+ network_info_list = datacall[2]
+ # 验证是否为列表(避免数据类型错误)
+ if not isinstance(network_info_list, list):
+ print("tuple 索引2不是列表,无法提取 priDNS")
+ return None
+
+ # 2. 第二步:从嵌套列表索引3获取 priDNS
+ pri_dns = network_info_list[3]
+ # 3. 验证 priDNS 有效性(可选,避免空值或无效格式)
+ if isinstance(pri_dns, str) and "." in pri_dns: # DNS通常含"."(如114.114.114.114)
+ print("dns合法")
+ pass
+ else:
+ print("priDNS 格式无效")
+ return
+ dmp_data = {
+ "wifiName": "",
+ "ipAddr": "{}".format(self.server_ip),
+ "dnsAddr": "{}".format(pri_dns),
+ "gateWayAddr": "192.168.0.1",
+ "signalLevel": "{}".format(signalLevel),
+ "battery": "{}".format(battery)
+ }
+ # # 生成有序JSON
+ # ordered_json = self.create_ordered_json(device_id, self.server_ip, signalLevel, battery)
+ # print(ordered_json)
+ token = EventMesh.publish("get_dev_token")
+ print("bz_dt = {}".format(token))
+ headers_T ={
+ "Content-Type":"application/json",
+ "bz-dt":"{}".format(token)
+ }
+ dmp_url = "http://app-api.raisound.com/dev/device/network/{}".format(device_id)
+ # dmp_url = "http://dmp.raisound.com/dmp-api/dev/device/network/{}".format(device_id)
+ print("url = {}".format(dmp_url))
+ # dmp_data =ujson.dumps(dmp_data)
+ print("data_type:{},data:{}".format(type(ujson.dumps(dmp_data)),ujson.dumps(dmp_data)))
+
+ try:
+ print("put")
+ request.put(dmp_url,data=ujson.dumps(dmp_data),headers = headers_T,timeout=5)
+ print("putover")
+ except Exception as e:
+ usys.print_exception(e)
+ print("dmp_update put error!!!!!\r\n")
+
+ def update_volume(self,event,msg):
+ self.VC_TTS_volume = msg
+ self.aud.setVolume(self.VC_TTS_volume//10)
+ EventMesh.publish("set_storage_config",["VC_TTS_volume",msg])
+ print("声音改为{}".format(msg))
def VC_30S_timer_cb(self, *args): #
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_30S_timer_cb_})
def VC_30S_timer_cb_(self):
+ # print('VC_30S_timer_cb_')
self.get_config_timer_count += 1
+ self.send_timer_count += 1
if self.get_config_timer_count >= 2*60*2:#2小时更新配置参数
self.get_config_timer_count = 0
try:
elif dev_type == "7PIN" or dev_type == "7PIN_coze":#柒牌
url = "http://ota.qipai.com/bz-cmp-api/api/config/{}".format(modem.getDevImei())
else:
- url = "http://dmp.raisound.com/bz-api/dev/config/{}".format(modem.getDevImei())
+ url = "http://dmp-dev.raisound.com/dmp-api/dev/config/{}".format(modem.getDevImei())
+ # url = "http://dmp.raisound.com/bz-api/dev/config/{}".format(modem.getDevImei())
print(url)
usys.print_exception(e)
if response != None:
response.close()
+ def play_tts(self,event = None,msg= None):
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.play_tts_cb,"data":msg})
+
+
+ def play_tts_open(self,event = None,msg= None):#播报tts并开启vc
+ print("play_tts_open:{}".format(msg))
+ self.AI_TTS_str = msg
+ # EventMesh.publish("AI_key_press")
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_VC_start})
+
+ def play_tts_single(self,event, msg):#单次传递音频文本
+ print("play_tts_single:{}".format(msg))
+ self.AI_TTS_str = msg
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_VC_start})
+ self.Close_flag = 1
+ def play_tts_cb(self,data):
+ try:
+ tts_str = data[0]
+ is_close_VC = data[1]
+ if tts_str != "":
+ self.AI_TTS_str = tts_str
+ if is_close_VC != None:
+ self.Close_flag = is_close_VC
+ if self.AI_VC_send_data_queue.empty()!=True:
+ self.AI_VC_send_data_queue.clear()
+ if self.AI_ASR_send_data_queue.empty()!=True:
+ self.AI_ASR_send_data_queue.clear()
+ EventMesh.publish("open_led_all")
+ self.AI_ASR_send_buf_len = 0
+ self.VC_Speech_End()
+ self.websocket_deconnect_VC()
+ self.AI_VC_start()
+
+ # EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Speech_End})
+ # EventMesh.publish("publish_AI_btnInfo",{"func":self.websocket_deconnect_VC})
+ # EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_VC_start})
+ except Exception as e:
+ usys.print_exception(e)
+ pass
def audio_cb(self,event):
if event == 0:
print('audio-play finish.!!!!!!')
def AI_key_double_press(self, event, msg):#双击按键
print("AI_key_double_press")
- self.Close_flag = 1
+ # self.Close_flag = 1
self.Close()
- EventMesh.publish("load_screen", {"screen": "main_menu"})
+ EventMesh.publish("UI_ai_close")
+ EventMesh.publish("return_prev_screen")
def AI_key_press(self, event, msg):#按键按下
+ # 测试闹钟功能
+ # EventMesh.publish("AI_alarm_open")
+ # EventMesh.publish("AI_add_alarm",[{"alarm_type":"单次闹钟","alarm_timestamp":1753071946,"repeat_day":"2025-07-21","repeat_min":0,"valid_time":"","alarm_timer":"12:25","alarm_content":"开会"}])
+ # return
print("AI_key_press")
+ EventMesh.publish("send_device_VC_state")#上传VC状态
self.get_config_timer_count = 0
self.key_state = 1
self.Close()
#if self.VC_record_state_flag >1:#如果在录音,就先停止录音
self.VC_Speech_End()
# return
- self.VC_Speech_Start()
+ # self.VC_Speech_Start()
self.AI_VC_start()
+ lv.img.cache_invalidate_src(None)
+ lv.img.cache_set_size(8)
EventMesh.publish("load_screen", {"screen": "UI_ai"})#ai画面
+ EventMesh.publish("audio_montage_play",["chenggong.mp3"])
# if dev_type != "7PIN":
# self.chenggong_tone()
# self.Close()
if self.AI_ASR_flag != 0:
return
- if self.VC_record_state_flag == 0:
-
+ if self.VC_record_state_flag == 0:
self.VC_record_thread_close()#关闭录音线程
+
_thread.stack_size(self.Audio_buf_size+8*1024)
self.VC_record_thread_id = _thread.start_new_thread(self.VC_record_thread,())
_thread.stack_size(8*1024)
except Exception as e:
usys.print_exception(e)
self.record_fd = open('/usr/record_data.pcm','w')
+ self.record_file_len = 0
if self.record_fd != None:
self.record_fd.write(read_buf)
print("write record:{}".format(len(read_buf)))
+ self.record_file_len+=len(read_buf)
+ if self.record_file_len>=200*1024:
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
+ print("write record:{}".format(len(read_buf)))
# count+=Record_len
# if count >150*1024:
# self.record_fd.close()
print("VC_record_thread:exit")
self.VC_record_thread_id = 0#线程退出
self.VC_record_thread_lock = 0
+
###################################################### VC ###################################################################################
def websocket_connect_VC(self):
print("websocket_connect_VC:{} e:{}!!!!!!!!!!!!!!!!!!!!!".format(self.AI_client_VC_isconnect,self.AI_client_VC_debug))
req_str = "vc/agent?is_auth={}".format(self.is_auth)
if(token):
- url = 'ws://{}/{}&dt={}'.format(self.server_ip,req_str,token)
+ # url = 'ws://{}/{}&dt={}'.format(self.server_ip,req_str,token)
+ url = 'ws://{}/vc/agent'.format(self.server_ip)
else:
url = 'ws://{}/{}'.format(self.server_ip,req_str)
#url = 'ws://115.190.94.208:22080/vc/coze?dt={}'.format(token)
-
+ #ws://118.145.158.207:22080/vc/agent
+ # url = "ws://ec2-3-81-87-67.compute-1.amazonaws.com:22080/vc/chat"
print("VC VC:url{}".format(url))
self.AI_client_VC = uwebsocket.Client.connect(url, debug=True)
#self.AI_WS_connect_Queue.put(self.AI_client_VC)
-
-
+
print("websocket_connect_VC:OK!!!!!!!!!!!!!!!!!!!!!")
except Exception as e: #网络连接异常
usys.print_exception(e)
print("websocket_error4")
-
def websocket_deconnect_VC(self):
#print("websocket_deconnect_VC {}!!!!!!!".format(self.AI_client_VC_isconnect))
print("websocket_deconnect_VC!!!!!!!")
self.AI_client_VC_recv_lock = 0
count+=1
+ # if self.VC_state >= VC_State_TTSStart:
+ # print("self.tts_in_data_len - self.tts_out_data_len = {}".format(self.tts_in_data_len - self.tts_out_data_len))
if self.VC_state >= VC_State_TTSStart and (self.tts_in_data_len - self.tts_out_data_len > 64*1024 or count>5):
count = 0
utime.sleep_ms(1)
if isinstance(recv_data, str):#返回的是字符串
print("VC VC:recv_data:{}".format(recv_data))
jsload_data = ujson.loads(recv_data)
- #print("AI_client_VC_recv jsload_data = {}".format(jsload_data))
-
+ # self.happy_list = ["开心","高兴","兴奋"]
+ # self.cry_list = ["委屈","难过","伤心","哭泣","受伤"]
+ # self.angry_list = ["愤怒","生气","不耐烦"]
+ # self.confused_list = ["疑惑","困惑"]
+ if jsload_data["event"] == "llm.completed":#只有类型为llm.completed的字符串可以来判断表情
+ if(any(item in recv_data for item in self.cry_list)):
+ print("识别到哭泣")
+ self.face_status = 1#变为哭泣
+ # elif(any(item in recv_data for item in self.cry_list)):
+ # print("识别到哭泣")
+ # self.face_status = 1#变为哭泣
+ elif(any(item in recv_data for item in self.angry_list)):
+ self.face_status = 2#变为愤怒
+ print("识别到愤怒")
+ elif(any(item in recv_data for item in self.confused_list)):
+ self.face_status = 3#变为疑惑
+ print("识别到疑惑")
+ else:
+ self.face_status = 0#变为正常
+ #print("face_status1={}".format(self.face_status))
if jsload_data["event"] == "started" :#会话开始
#payload = jsload_data["payload"]
# self.VC_dialog_id = payload["dialog_id"]
EventMesh.publish("open_led_blue")
print("VC:Started!!!!!!!!\r\n")
- if self.AI_TTS_str == "":
+ if self.AI_TTS_str == "" and self.AI_music_str == "":
#开始上传语音
+ self.draw_result = 0
if dev_type != "7PIN" and dev_type != "7PIN_coze":
- self.chenggong_tone()
+ pass
+ # self.chenggong_tone()
if self.VC_mode == 0 :
self.VC_record_state_flag =2
else:
EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_client_VC_send_speech})
- else:
+ elif self.AI_TTS_str != "" and self.AI_music_str == "":
EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_client_VC_synthesis})
+
+ elif self.AI_TTS_str == "" and self.AI_music_str != "":
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_client_VC_sing})
+
self.VC_state = VC_State_None
elif jsload_data["event"] == "config.update" :#配置更新中,需要停止录音
self.VC_state = VC_State_End
EventMesh.publish("open_led_blue")
elif jsload_data["event"] == "asr.completed" :#asr 终止的标识
print("self.commands_mode:{}".format(self.commands_mode))
- if self.commands_mode ==2:
+ if self.commands_mode ==1:
ret= self.check_text(self.AI_ASR_str)
if ret == 0:#配置指令
if self.is_VAD == 0:
if self.VC_record_state_flag == 1:#llm返回数据还没停止,就先停止
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Speech_End})
+ #print("AI_client_VC_recv jsload_data = {}".format(jsload_data))
elif jsload_data["event"] == "tts.started" :#tts开始
self.VC_state = VC_State_TTSStart
if self.is_VAD == 0:
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Speech_End})
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Play_Start})
-
#self.VC_Play_Start()
EventMesh.publish("open_led_green")#绿色
elif jsload_data["event"] == "tts.completed" :#tts结束
EventMesh.publish("open_led_green")#绿色
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Play_Start})
- self.LocalRespondingEnded_timerout = 8
+ self.LocalRespondingEnded_timerout = 0
self.VC_state = VC_State_TTSEnd
pass
elif jsload_data["event"] == "canceled" :#打断
+ self.VC_Play_End()#音频设备关闭
+ self.draw_result = 0
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Speech_Start_now})#开始录音
self.VC_state = VC_State_None
+ EventMesh.publish("send_device_VC_state")#上传VC状态
elif jsload_data["event"] == "completed" :#会话结束
#EventMesh.publish("open_led_green")#绿色
-
- self.LocalRespondingEnded_timerout = 8
+ self.LocalRespondingEnded_timerout = 3
self.VC_state = VC_State_End
+ EventMesh.publish("send_device_VC_state")#上传VC状态
pass
elif jsload_data["event"] == "command" :#命令匹配
ret = -1
elif jsload_data["event"] == "failed":#接口返回错误
if jsload_data["payload"]["error"] == "concurrency_limit_exceeded":
EventMesh.publish("publish_AI_btnInfo",{"func":self.concurrency_limit_exceeded_tone})
-
+ print("错误")
#utime.sleep_ms(4000)
else:
#print("buf已满,等待释放:buf_len:{},count_tmp:{}".format(buf_len,count_tmp))
except Exception as e:
usys.print_exception(e)
- EventMesh.publish("publish_AI_btnInfo",{"func":self.put_record_data,"data":[recv_data,""]})
- utime.sleep_ms(1)
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.put_record_data,"data":[recv_data,""]})
+ utime.sleep_ms(1)
+ # print("self.tts_in_data_len - self.tts_out_data_len = {}".format(self.tts_in_data_len - self.tts_out_data_len))
except Exception as e:
usys.print_exception(e)
return 0
if text.find("版本") != -1 :
sourceVersion = versions.Build_Time
- self.AI_TTS_str ="Mr-Seven-"+sourceVersion
+ self.AI_TTS_str ="JSWM-"+sourceVersion
return 0
if text.find("服务器地址") != -1 :
self.AI_TTS_str ="服务器地址"+self.server_ip
if len(text)<20 and (text.find("再见") != -1 or text.find("拜拜") != -1 or text.find("关闭对话") != -1):
#EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
self.AI_TTS_str = "好嘞,再见,我们下次再聊"
- EventMesh.publish("load_screen", {"screen": "main_menu"})
+ EventMesh.publish("UI_ai_close")
+ EventMesh.publish("return_prev_screen")
self.Close_flag = 1
return 0
if len(text)<12 and (text.find("关机") != -1 ):
EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
+ utime.sleep_ms(400)
EventMesh.publish("Power_off")
return 1
except Exception as e:
EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
EventMesh.publish("Power_off")
return 1
+ if text.find("闹钟设定") != -1:
+ print("闹钟设定")
+ alarm_timer_sta = EventMesh.publish("alarm_get_statu")
+ if alarm_timer_sta == 0 :
+ EventMesh.publish("AI_alarm_open")#开启轮询
+ alarm_timer_sta = 1
+ text = cmd["command"]["params_json"]
+ print("params_json:{}".format(text))
+
+ try:
+ alarm = ujson.loads(text)
+ if alarm["is_right"] == True:#大模型判断闹钟格式以及内容正确
+ add_alarm_tmp = EventMesh.publish("AI_add_alarm",alarm["alarm"])
+ if add_alarm_tmp[0]> 0:
+ self.AI_TTS_str = add_alarm_tmp[1]
+ return 0
+ else:
+ pass
+ except Exception as e:
+ usys.print_exception(e)
+ if text.find("取消闹钟") != -1 :
+ EventMesh.publish("AI_delete_alarm")
+ EventMesh.publish("AI_alarm_close")
+ self.AI_TTS_str = "闹钟列表已经清空"
+ return 0
+ if text.find("关帝灵签结果") != -1 :
+ #占卜师角色,把说的状态改为抽签结果
+ text = cmd["command"]["params_json"]
+ text = ujson.loads(text)
+ EventMesh.publish("draw_handle",text["lots_result"])
+ self.AI_TTS_str = text["lot_content"]
+ return 0
+ if text.find("播放音乐") != -1 :
+ #音乐播放器角色,播放音乐
+ text = cmd["command"]["params_json"]
+ text = ujson.loads(text)
+ self.AI_music_str = text["mp3"]
+ return 0
except Exception as e:
usys.print_exception(e)
self.AI_TTS_str = cmd["command"]["fail_prompt"]
return -1
+ def draw_handle(self,event,msg):
+ if msg == "大吉":
+ self.draw_result = 1
+ elif msg == "中吉":
+ self.draw_result = 1
+ elif msg == "吉":
+ self.draw_result = 1
+ elif msg == "末吉":
+ self.draw_result = 1
+
def check_text(self,text):
print("check_text:len:{}".format(len(text)))
if len(text)>60:
if text.find("音量") != -1 or text.find("声音") != -1:
if text.find("加") != -1 or text.find("增") != -1:
self.VC_TTS_volume += 10
- if self.VC_TTS_volume > 110:
+ if self.VC_TTS_volume > 100:
#EventMesh.publish("audio_montage_play",["yinliangyizuida.mp3"])
#self.aud.play(1,0,'U:/static/yinliangyizuida.mp3')#音量已最大
self.AI_TTS_str = "音量已最大"
- self.VC_TTS_volume = 110
+ self.VC_TTS_volume = 100
else:
self.aud.setVolume(self.VC_TTS_volume //10)
EventMesh.publish("set_storage_config",["VC_TTS_volume",self.VC_TTS_volume])
if text.find("服务器地址") != -1 :
self.AI_TTS_str ="服务器地址"+self.server_ip
return 0
-
+ if text.find("闹钟列表") != -1 :
+ EventMesh.publish("read_alarm_list")
+ return 0
if text.find("讲话") != -1 or text.find("说话") != -1:
if text.find("快") != -1 and text.find("太") == -1 :
self.speech_rate += 10
if self.VC_Play_flag == 0:
try:
if self.VC_play_TYPE == VC_play_TYPE_PCM:
- if self.play_pcm == None:
+ if self.play_pcm == None :
self.play_pcm = audio.Audio.PCM(0,1,self.VC_play_samplerate,1,1,2)
# self.play_pcm.setVolume(11)
self.play_pcm.setVolume(self.VC_TTS_volume // 10)
EventMesh.publish("publish_AI_btnInfo",{"func":self.websocket_error,"data":"接口超时了。请重试"})
self.ud_error(["VC",self.VC_taskid])
else:
+ EventMesh.publish("UI_ai_close")
EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
EventMesh.publish("load_screen", {"screen": "main_menu"})
pass
self.Close_flag = 0
EventMesh.publish("publish_AI_btnInfo",{"func":self.Close})
EventMesh.publish("load_screen", {"screen": "main_menu"})
+ EventMesh.publish("send_device_VC_state")#上传VC状态
else:
#utime.sleep_ms(1000)
EventMesh.publish("publish_AI_btnInfo",{"func":self.VC_Play_End})
# self.VC_pingping_timerout = 0
# self.asr_pingping_timerout = 0
print("AI_VC_start5")
+
#开始会话
def AI_client_VC_start_requset(self):
+ print("AI_client_VC_start_requset")
voice="zh_male_wennuanahu_moon_bigtts"
try:
voice = self.VC_TTS_voice_type[self.VC_TTS_voice_key]["voice"]
except Exception as e:
usys.print_exception(e)
#voice="zh_female_dongmanxiaoyang_moon_bigtts"
-
+ # #海外服务器
+ # json_data = \
+ # {
+ # "event": "start",
+ # "payload": {
+ # "simple_response": False,
+ # "device_id": modem.getDevImei(),
+ # "user_agent": "AudioClientWithAEC/1.0",
+ # "dialog_attributes": {
+ # "provider": "openai",
+ # "cfg": {
+ # "disable_empty_prompt": True,
+ # "greeting":{
+ # "enabled": True,
+ # "content": "Hi! What can I do for you.",
+ # },
+ # "openai_option": {
+ # "model": "gpt-4o",
+ # "system": {
+ # "type": "file",
+ # "content": "1567d9e19ac09269d8ce6c887494ff01" # 林悦
+ # },
+ # }
+ # }
+ # },
+ # "outbound_attributes": {
+ # "provider": "azure",
+ # "cfg": {
+ # "format": "pcm",
+ # "sample_rate": 16000,
+ # "bit_rate": 16,
+ # "channel": 1,
+ # "volume": 100,
+ # # "voice": "en-US-AvaMultilingualNeural", #"cosyvoice-v2-amp-2f7d423",# "longjielidou",
+ # "voice":"zh-CN-XiaoxiaoNeural",# mandarin
+ # "speech_rate": 0,
+ # "chunk_interval_ms": 10
+ # }
+ # },
+ # "inbound_attributes": {
+ # "provider": "azure",
+ # "disable_vad": False,
+ # "vad_silence": 200,
+ # "interrupt_options": {
+ # "concatenate_results": True,
+ # "thinking_time_only": True,
+ # # "keyword_interrupt": True,
+ # # "interrupt_keywords": ["停止", "打断","打断一下", "等一下", "别说了", "打住"]
+ # },
+ # "cfg": {
+ # "format": "pcm",
+ # "sample_rate": 16000,
+ # "bit_rate": 16,
+ # "channel": 1,
+ # "enable_punctuation": True,
+ # "enable_itn": True,
+ # "keywords": [
+ # "停止",
+ # "打断",
+ # "打断一下",
+ # "等一下",
+ # "别说了",
+ # "打住"
+ # ]
+ # }
+ # }
+ # }
+ # }
json_data = \
{
"header": {
"commands":self.commands,
}
}
+
# "bot_id":"7481164663863459850",#鸭子
# "workflow_id":"7480485093845991443",
# "bot_id":"7462617881076351002",#语言助手
if self.VC_mode == 1:#单对话模式
self.AI_client_VC_send(ujson.dumps(json_data))
-
-
-
-
-
+
self.VC_state = VC_State_SpeechStart
#结束上传语音
# if self.VC_state == VC_State_RequestToRespond:
# print("AI_client_VC_RequestToRespond 重复 tts_str:{}\nasr_str:{}".format(self.AI_TTS_str,self.AI_ASR_str))
self.AI_client_VC_send(ujson.dumps(json_data))
-
+
+ #唱歌
+ def AI_client_VC_sing(self):
+ json_data = \
+ {
+ "event": "audio.convert",
+ "payload": {
+ "audio_convert_request": {
+ "audio_url": self.AI_music_str,
+ "bit_depth": 16,
+ "channels": 1,
+ "sample_rate": 16000,
+ "target_format": "pcm"
+ }
+ }
+ }
+
+ self.AI_client_VC_send(ujson.dumps(json_data))
+ print("AI_client_VC_sing!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
def chenggong_tone(self):
EventMesh.publish("audio_montage_play",["chenggong.mp3"])
def send_tone(self):
if tmp != 0:
print("2playStream:error tmp:{} data len:{}!!!!!!!!!!!!".format(tmp,len(data[0])))
- # # #播放失败的时候填充WAV头
- # data_len = len(data[0])
- # data_len_b = data_len.to_bytes(4,'little')#数据长度转16进制数组
- # h_data = [ 0x52 ,0x49 ,0x46 ,0x46 #,0x24 ,0x00 ,0x00 ,0x00 #文件标识、文件大小
- # ,0x57 ,0x41 ,0x56 ,0x45 ,0x66 ,0x6D ,0x74 ,0x20 #文件格式、格式块标识符
- # ,0x10 ,0x00 ,0x00 ,0x00 ,0x01 ,0x00 ,0x01 ,0x00 ,0x80 ,0x3E ,0x00 ,0x00 #格式块大小4、音频格式2、声道数2、采样率4
- # ,0x80 ,0x3E ,0x00 ,0x00 ,0x02 ,0x00 ,0x10 ,0x00 ,0x64 ,0x61 ,0x74 ,0x61]#每秒字节数4、数据块对齐2、位深度2、data4
- # h_data_b = bytes(h_data)
- # file_len = data_len+len(h_data_b)+4+4
- # file_len_b = file_len.to_bytes(4,'little')#文件长度转16进制数组
- # h_data_b = h_data_b[:4]+file_len_b+h_data_b[4:]+data_len_b
- # #self.aud.playStream(2, h_data_b)#播放音频流
- # tmp= self.aud.playStream(2, h_data_b+data[0])#播放音频流
- # print("3playStream:tmp:{} !!!!!!!!!!!!".format(tmp))
mem = gc.mem_free()
self.VC_Thinking_timerout = 0
self.VC_satrt_flag = 0
self.AI_TTS_str = ""
+ self.AI_music_str = ""
self.AI_ASR_str = ""
self.AI_ASR_str_tmp = ""
self.AI_ASR_flag = 0
self.tts_in_data_len = 0
self.tts_out_data_len = 0
#必须先销毁线程,不然线程会容易报错
-
+ EventMesh.publish("send_device_VC_state")#上传VC状态
try:
self.AI_audio_queue_thread_close()#销毁音频线程
except Exception as e:
self.AI_VC_send_data_queue_thread_close()#销毁数据发送线程
except Exception as e:
usys.print_exception(e)
-
self.VC_Speech_End()
print("ai_VC Close1.1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
--- /dev/null
+#ai闹钟
+import EventMesh
+import usys
+import ujson
+import osTimer
+import utime
+class AI_alarm():
+ """
+ sjon格式{
+ "alarm_type":"重复闹钟", #闹钟类型。示例值:重复闹钟(喝水提醒,重复每天闹钟)、单次闹钟(会议提醒)
+ "alarm_timestamp":1750402089,#单次闹钟触发时间戳,单位:秒。只有单次闹钟有效
+ "repeat_day":["周一","周二","周三","2025-06-20"],#按天循环规则。示例值:周一,周五,每天,2025-06-20(自定义日期)
+ "repeat_min":60,#当天是否按多少分钟循环,为0时每天只响应一次,为120时每隔2小时触发一次。示例值:120
+ "valid_time":"9-18",# 当天循环有效时间,只有当repeat_min不为0时有效。repeat_min=60时,在有效时间内1小时循环响应1次。等于空值时,当天24小时有效
+ "alarm_timer":"06:50",#触发时间。示例值:06:50 ,6点50分时触发闹钟
+ "alarm_content":"周例会",#闹钟提醒内容。为空时,播放本地默认音频,不为空时,tts循环播放内容。示例值:"喝水提醒"
+ }
+ """
+ #最多只能设置五个闹钟
+ def __init__(self):
+ self.alarm_array = EventMesh.publish("get_storage_config","alarm_array")#读取闹钟数组
+ if self.alarm_array is None:
+ self.alarm_array =[]
+ print("self.alarm_array =[]")
+ self.AI_alarm_timer = osTimer()
+ self.alarm_min_repeat_tmp = 0
+ self.alarm_min_one_tmp = 0
+ self.alarm_count = len(self.alarm_array)#闹钟个数
+ print("闹钟个数 ={}".format(self.alarm_count))
+ self.alarm_list_text = EventMesh.publish("get_storage_config","alarm_list_text")#闹钟文本列表
+ if self.alarm_list_text is None:
+ self.alarm_list_text =[]
+ print("闹钟列表:{}".format(self.alarm_list_text))
+ self.alarm_timer_sta = 0#alarm定时器开启状态 0为关闭,1为开启
+ self.used_numbers = set()#已经被使用的闹钟编号集合
+ self.circle_alarm_flag = [] #闹钟重复判断标志列表
+ EventMesh.subscribe("AI_alarm_close",self.AI_alarm_close)
+ EventMesh.subscribe("AI_alarm_open",self.AI_alarm_open)
+ EventMesh.subscribe("AI_alarm_poll_extern",self.AI_alarm_poll_extern)
+ EventMesh.subscribe("AI_add_alarm",self.AI_add_alarm)
+ EventMesh.subscribe("alarm_get_statu",self.alarm_get_statu)
+ EventMesh.subscribe("get_have_alarm",self.get_have_alarm)
+ EventMesh.subscribe("AI_delete_alarm",self.AI_delete_alarm)
+ EventMesh.subscribe("read_alarm_list",self.read_alarm_list)
+ def alarm_get_statu(self,event=None,msg=None):
+ print("alarm_get_statu = {}".format(self.alarm_timer_sta))
+ return self.alarm_timer_sta
+
+ def AI_alarm_open(self,event=None,msg=None):
+ print("AI_alarm_open")
+ self.alarm_timer_sta = 1
+ self.AI_alarm_timer.start(20000, 1, self.AI_alarm_timer_cb)
+
+ def AI_alarm_timer_cb(self, *args):
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_alarm_poll})
+ pass
+
+ def get_have_alarm(self,event,msg):
+ self.alarm_array = EventMesh.publish("get_storage_config","alarm_array")#读取闹钟数组
+ if self.alarm_array ==None:
+ return 0
+ else:
+ return 1
+
+ def AI_alarm_poll(self):#轮询调用
+ is_alarm = 0 #是否触发闹钟
+ alarm_TTS_str =""#闹钟播放tts字符串
+ repeat_day_flag = 0
+ alarm_timer_flag = 0
+ # print("AI_alarm_poll111")
+ if len(self.alarm_array) == 0:
+ return
+ print("self.alarm_array = {}".format(self.alarm_array))
+ if all(element is None for element in self.alarm_array):
+ print("删除所有闹钟")
+ self.AI_delete_alarm()#删除所有闹钟
+ self.AI_alarm_close()#关闭相关定时器
+ return
+ if len(self.alarm_array)>0:
+ # print("AI_alarm_poll222")
+ try:
+ now_time = utime.localtime()
+ old_minute = [None] * len(self.alarm_array)
+ cnt = -1#记录到了闹钟列表第几位
+ for _alarm in self.alarm_array :
+ cnt += 1
+ if _alarm is None:
+ continue
+ if len(self.circle_alarm_flag) >0:
+ print("self.circle_alarm_flag[cnt] = {}".format(self.circle_alarm_flag[cnt]))
+ if self.circle_alarm_flag[cnt] == 1:#已触发过一次
+ if old_minute[cnt] is not None:
+ if now_time[4] > old_minute[cnt]:
+ self.circle_alarm_flag[cnt] = 0#清空标志位
+ old_minute[cnt] = now_time[4]
+ if _alarm["alarm_type"] == "单次":
+ #判断闹钟数字合法
+ repeat_day = _alarm["repeat_day"][0]
+ Y_M_D = repeat_day.split('-')
+ alarm_timer = _alarm["alarm_timer"]
+ H_M = alarm_timer.split(':')
+ time_tuple = utime.localtime()#获取当前日期&时间的元组
+ set_year = int(Y_M_D[0])
+ set_month = int(Y_M_D[1])
+ set_day = int(Y_M_D[2])
+ set_hour = int(H_M[0])
+ set_minute = int(H_M[1])
+ year_now = time_tuple[0]
+ month_now = time_tuple[1]
+ day_now = time_tuple[2]
+ hour_now = time_tuple[3]
+ minute_now = time_tuple[4]
+ if set_year < year_now or (set_year == year_now and set_month < month_now) or \
+ (set_year == year_now and set_month == month_now and set_day < day_now):
+ print("闹钟日期已过期,已清除闹钟{}".format(_alarm["number"]))
+ self.used_numbers.remove(self.alarm_array[cnt]["number"])#从闹钟名集合中移除
+ self.alarm_array.pop(cnt)
+ EventMesh.publish("set_storage_config",["alarm_array",self.alarm_array])
+ self.alarm_list_text.pop(cnt)
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ continue
+ if (set_year == year_now and set_month == month_now and set_day == day_now) and set_hour < hour_now or (set_hour == hour_now and set_minute < minute_now):
+ print("闹钟日期已过期,已清除闹钟{}".format(_alarm["number"]))
+ self.used_numbers.remove(self.alarm_array[cnt]["number"])#从闹钟名集合中移除
+ self.alarm_array.pop(cnt)
+ EventMesh.publish("set_storage_config",["alarm_array",self.alarm_array])
+ self.alarm_list_text.pop(cnt)
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ continue
+
+ if _alarm["alarm_type"] == "重复":
+ #print("AI_alarm_poll333")
+ weekday = now_time[6]
+ weekday_str = ""
+ if weekday == 0:
+ weekday_str = "周一"
+ elif weekday == 1:
+ weekday_str = "周二"
+ elif weekday == 2:
+ weekday_str = "周三"
+ elif weekday == 3:
+ weekday_str = "周四"
+ elif weekday == 4:
+ weekday_str = "周五"
+ elif weekday == 5:
+ weekday_str = "周六"
+ elif weekday == 6:
+ weekday_str = "周日"
+ week = _alarm["repeat_day"]
+ for _week in week :
+ if weekday_str == _week:#符合周判断
+ repeat_day_flag = 1
+ break
+ if repeat_day_flag == 0:#周不符合
+ continue
+ if _alarm["repeat_min"] ==0: #每天只提醒一次,已添加闹钟1,周一,周二,周三,6:50分提醒您周例会
+ alarm_timer = _alarm["alarm_timer"]
+ H_M = alarm_timer.split(':')
+ if len(H_M) != 2:
+ continue
+ hour = int(H_M[0])
+ min = int(H_M[1])
+ if hour == now_time[3] and min == now_time[4]:
+ alarm_timer_flag =1
+ else:#时间不符合
+ continue
+
+
+ if alarm_timer_flag==1:#时间符合,触发闹钟
+ alarm_TTS_str += _alarm["alarm_content"]
+ is_alarm = 1
+ break
+ else:#每天循环间提醒。已添加闹钟1,周一,周二,周三,9点到18点每隔60分钟提醒您喝水
+ valid_time = _alarm["valid_time"]
+ H_H = valid_time.split('-')
+ if len(H_H) != 2:
+ continue
+ start_time = H_H[0].split(':')
+ end_time = H_H[1].split(':')
+ if len(start_time)<2 or len(end_time)<2:
+ continue
+ start_time_int = int(start_time)
+ end_time_int = int(end_time)
+ now_h = now_time[3]
+ if now_h>=start_time_int and now_h <= end_time_int:#在有效时间范围
+ now_m = now_time[4]
+ repeat_min_int = _alarm["repeat_min"]
+ if (now_m + repeat_min_int)%repeat_min_int == 0 and self.alarm_min_repeat_tmp != now_m:#每分钟符合
+ self.alarm_min_repeat_tmp = now_m
+ alarm_TTS_str += _alarm["alarm_content"]
+ is_alarm = 1
+ continue
+
+ else:
+ continue
+#EventMesh.publish("AI_add_alarm",{"alarm_type":"单次闹钟","alarm_timestamp":1752739511,"repeat_day":"2025-07-17","repeat_min":0,"valid_time":"","alarm_timer":"16:05","alarm_content":"开会"})
+ elif _alarm["alarm_type"] == "单次":
+ # print("AI_alarm_poll444")
+ alarm_timer = _alarm["alarm_timer"]
+ H_M = alarm_timer.split(':')
+ if len(H_M) != 2:
+ print("len(H_M) != 2")
+ continue
+ repeat_day = _alarm["repeat_day"][0]
+ Y_M_D = repeat_day.split('-')
+ #print("Y_M_D:{}".format(Y_M_D))
+ if len(Y_M_D)<3:
+ print("len(Y_M_D)<3")
+ continue
+ year_int = int(Y_M_D[0])
+ month_int = int(Y_M_D[1])
+ day_int = int(Y_M_D[2])
+ hour_int = int(H_M[0])
+ minute_int = int(H_M[1])
+ if year_int == now_time[0] and month_int == now_time[1]and day_int == now_time[2]and hour_int == now_time[3]and minute_int == now_time[4]:
+ if self.alarm_min_one_tmp != now_time[4]:
+ self.alarm_min_one_tmp = now_time[4]
+ alarm_TTS_str += _alarm["alarm_content"]
+ is_alarm = 1
+ print("self.alarm_min_one_tmp != now_time[4]")
+ break #发现闹钟存在直接跳出循环
+ #ret_str += "{},{}点{}分提醒您:{}。".format(_alarm["repeat_day"],H_M[0],H_M[1],_alarm["alarm_content"])
+ # print("AI_alarm_poll555")
+ if is_alarm == 1 :
+ if _alarm["alarm_type"] == "重复":
+ if len(self.circle_alarm_flag) > 0:
+ if self.circle_alarm_flag[cnt] == 1:#已触发过一次
+ print("闹钟已触发过一次")
+ return
+ EventMesh.publish("audio_montage_play",["chenggong.mp3"])
+ EventMesh.publish("play_tts",["小瑞提醒您该{}了,小瑞提醒您该{}了,小瑞提醒您该{}了".format(alarm_TTS_str,alarm_TTS_str,alarm_TTS_str),1])
+ print("闹钟提醒:小瑞提醒您该{}了,小瑞提醒您该{}了,小瑞提醒您该{}了".format(alarm_TTS_str,alarm_TTS_str,alarm_TTS_str))
+ if _alarm["alarm_type"] == "单次":
+ self.used_numbers.remove(self.alarm_array[cnt]["number"])#从闹钟名集合中移除
+ self.alarm_array.pop(cnt)#删除闹钟元素
+ self.alarm_list_text.pop(cnt)#删除读闹钟列表元素
+ EventMesh.publish("set_storage_config",["alarm_array",self.alarm_array])
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ elif _alarm["alarm_type"] == "重复":
+ required_length = cnt + 1
+ current_length = len(self.circle_alarm_flag)
+ if current_length < required_length:
+ # 补充缺失的位置,用默认值(如0)填充
+ self.circle_alarm_flag.extend([0] * (required_length - current_length))
+ self.circle_alarm_flag[cnt] = 1
+ except Exception as e:
+ usys.print_exception(e)
+ pass
+
+ def AI_alarm_poll_extern(self,event=None,msg=None):#外部调用轮询间隔,关闭定时器调用
+ self.AI_alarm_timer.stop()
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.AI_alarm_poll})
+
+ def AI_add_alarm(self,event=None,alarm_array_u=None):#添加闹钟数组
+ ret = 0
+ alarm_array_tmp = self.alarm_array
+ if alarm_array_tmp is None:
+ alarm_array_tmp =[]
+ if self.alarm_count >= 10:
+ tts = "闹钟列表已满,请清除闹钟后再设置"
+ return [1,tts]
+ #已添加闹钟1,周一,周二,周三,6:50分提醒您周例会
+ ret_str = "已添加"
+ print("AI_add_alarm:{}".format(alarm_array_u))
+ try:
+ for _alarm in alarm_array_u :
+ if ("alarm_content" in _alarm )and (_alarm["alarm_type" ] == "重复" or _alarm["alarm_type" ] == "单次" ):#简单的判断这个配置是合法的
+ # #判断闹钟数字合法
+ repeat_day = _alarm["repeat_day"][0]
+ Y_M_D = repeat_day.split('-')
+ alarm_timer = _alarm["alarm_timer"]
+ H_M = alarm_timer.split(':')
+ # time_tuple = utime.localtime()#获取当前日期&时间的元组
+ # set_year = int(Y_M_D[0])
+ # set_month = int(Y_M_D[1])
+ # set_day = int(Y_M_D[2])
+ # set_hour = int(H_M[0])
+ # set_minute = int(H_M[1])
+ # year_now = time_tuple[0]
+ # month_now = time_tuple[1]
+ # day_now = time_tuple[2]
+ # hour_now = time_tuple[3]
+ # minute_now = time_tuple[4]
+ # if set_year < year_now or (set_year == year_now and set_month < month_now) or \
+ # (set_year == year_now and set_month == month_now and set_day < day_now):
+ # tts = "您设置的闹钟日期已过期,请重新设置"
+ # return [1,tts]
+ # if set_month > 12 or set_month < 1 or set_day > 31 or set_day <1:
+ # tts = "您设置的闹钟日期非法,请重新设置"
+ # return [1,tts]
+ # if set_hour < hour_now or (set_hour == hour_now and set_minute < minute_now):
+ # tts = "您设置的闹钟时间已过期,请重新设置"
+ # return [1,tts]
+ print(" AI_add_alarm 1111!!!")
+ ret +=1
+
+ number = 0#闹钟编号
+ #计算闹钟编号
+ for i in range(1, 11):
+ if i not in self.used_numbers:#当i不在集合中时,说明闹钟名未被添加,可以加入闹钟集合
+ self.used_numbers.add(i)
+ number = i #为当前闹钟赋值
+ break
+ #将键加入闹钟字典
+ _alarm["number"] = number
+
+ #加入设定列表
+ alarm_array_tmp.append(_alarm)
+ ret_str += "闹钟{},".format(number)
+ self.alarm_count = len(alarm_array_tmp)#闹钟总数
+
+ if _alarm["alarm_type"] == "重复":
+ print(" AI_add_alarm 2222!!!")
+ if _alarm["repeat_min"] ==0: #每天只提醒一次,已添加闹钟1,周一,周二,周三,6:50分提醒您周例会
+ # if len(H_M) != 2:
+ # tts = "闹钟信息不完整,请重新设置"
+ # #移出设定列表
+ # alarm_array_tmp.remove(_alarm)
+ # ret_str = ""
+ # self.alarm_count = len(alarm_array_tmp)#闹钟总数
+ # return [1,tts]
+ ret_str += "{},{}点{}分提醒您{}。".format(_alarm["repeat_day"],H_M[0],H_M[1],_alarm["alarm_content"])
+ #添加闹钟描述文本
+ self.alarm_list_text.append("闹钟{}:重复闹钟,{},{}点{}分提醒您{}".format(number,_alarm["repeat_day"],H_M[0],H_M[1],_alarm["alarm_content"]))
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ else:#每天循环间提醒。已添加闹钟1,周一,周二,周三,9点到18点每隔60分钟提醒您喝水
+ valid_time = _alarm["valid_time"]
+ H_H = valid_time.split('-')
+ # if len(H_H) != 2:
+ # tts = "闹钟信息不完整,请重新设置"
+ # #移出设定列表
+ # alarm_array_tmp.remove(_alarm)
+ # ret_str = ""
+ # self.alarm_count = len(alarm_array_tmp)#闹钟总数
+ # return [1,tts]
+ start_time = H_H[0].split(':')
+ end_time = H_H[1].split(':')
+ # if len(start_time)<2 or len(end_time)<2:
+ # tts = "闹钟信息不完整,请重新设置"
+ # #移出设定列表
+ # alarm_array_tmp.remove(_alarm)
+ # ret_str = ""
+ # self.alarm_count = len(alarm_array_tmp)#闹钟总数
+ # return [1,tts]
+ #添加闹钟描述文本
+ self.alarm_list_text.append("闹钟{}:重复闹钟,{},{}点{}分到{}点{}分,每隔{}分钟提醒您{}。".format(number,_alarm["repeat_day"][0],
+ start_time[0],start_time[1],end_time[0],end_time[1],
+ _alarm["repeat_min"],_alarm["alarm_content"]))
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ ret_str += "{},{}点{}分到{}点{}分,每隔{}分钟提醒您{}。".format(_alarm["repeat_day"][0],
+ start_time[0],start_time[1],end_time[0],end_time[1],
+ _alarm["repeat_min"],_alarm["alarm_content"])
+ elif _alarm["alarm_type"] == "单次":
+ print(" AI_add_alarm 3333!!!")
+ # if len(H_M) != 2:
+ # tts = "闹钟信息不完整,请重新设置"
+ # #移出设定列表
+ # alarm_array_tmp.remove(_alarm)
+ # ret_str = ""
+ # self.alarm_count = len(alarm_array_tmp)#闹钟总数
+ # return [1,tts]
+ # if len(Y_M_D)<3:
+ # tts = "闹钟信息不完整,请重新设置"
+ # #移出设定列表
+ # alarm_array_tmp.remove(_alarm)
+ # ret_str = ""
+ # self.alarm_count = len(alarm_array_tmp)#闹钟总数
+ # return [1,tts]
+ #添加闹钟描述文本
+ self.alarm_list_text.append("闹钟{}:单次闹钟,{}年{}月{}日,{}点{}分提醒您:{}。".format(number,Y_M_D[0],Y_M_D[1],Y_M_D[2],H_M[0],H_M[1],_alarm["alarm_content"]))
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ ret_str += "{}年{}月{}日,{}点{}分提醒您:{}。".format(Y_M_D[0],Y_M_D[1],Y_M_D[2],H_M[0],H_M[1],_alarm["alarm_content"])
+ # EventMesh.publish("play_tts_single",ret_str)
+ print("配置成功")
+ else:
+ return [-1]
+
+ except Exception as e:
+ usys.print_exception(e)
+ return [-1]
+
+ if ret != 0:#当有有效闹钟数据时
+ print("保存闹钟新建数据")
+ self.alarm_array = alarm_array_tmp
+ print("self.alarm_array = {}".format(self.alarm_array))
+ EventMesh.publish("set_storage_config",["alarm_array",self.alarm_array])
+ return [ret,ret_str]
+
+ def read_alarm_list(self,event=None,Num=None):#读闹钟全列表
+ alarmlist_TTS_str =""#闹钟全列表播放tts字符串
+ if len(self.alarm_list_text) == 0:
+ alarmlist_TTS_str = "当前闹钟列表没有闹钟信息"
+ EventMesh.publish("play_tts_single",alarmlist_TTS_str)
+ return
+ alarmlist_TTS_str += "当前闹钟信息如下:"
+ for count in self.alarm_list_text:
+ alarmlist_TTS_str += count
+
+ EventMesh.publish("play_tts_single",alarmlist_TTS_str)
+ def AI_delete_alarm(self,event=None,Num=None):#删除闹钟
+ self.alarm_array =[]#闹钟队列清空
+ EventMesh.publish("set_storage_config",["alarm_array",self.alarm_array])
+ self.alarm_list_text =[]#闹钟队列清空
+ EventMesh.publish("set_storage_config",["alarm_list_text",self.alarm_list_text])
+ self.alarm_count = 0
+ self.used_numbers.clear()#清空闹钟名集合
+
+ def AI_alarm_close(self,event=None,Num=None):
+ print("AI_alarm_close")
+ self.alarm_timer_sta = 0
+ self.AI_alarm_timer.stop()
+
no_add_alarm_img = lv.img(clk_list_screen1_1)
no_add_alarm_img.set_pos(65, 0)
no_add_alarm_img.set_size(110, 140)
-no_add_alarm_img.set_src("E:/static/IMAGE_IDLE_SCREEN_ALARM_ICON_NEW.png")
+no_add_alarm_img.set_src("E:/static/alarm.png")
no_add_alarm_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
#暂未添加闹钟
popup_alarm_img = lv.img(popup_alarm_screen)
-popup_alarm_img.set_pos(63, 60)
-popup_alarm_img.set_size(110, 140)
-popup_alarm_img.set_src("E:/static/IMAGE_IDLE_SCREEN_ALARM_ICON_NEW.png")
+popup_alarm_img.set_pos(0, 0)
+popup_alarm_img.set_size(240, 320)
+popup_alarm_img.set_src("E:/static/alarm.png")
popup_alarm_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
popup_alarm_time = lv.label(popup_alarm_screen)
def exit_alarm_page(self,*arges):
EventMesh.publish("system_sleep_rest")#防止黑屏
self.alarm_count+=1
- if self.alarm_count > 60:
+ if self.alarm_count > 10:
self.alarm_count = 0
self.aud.stop()
self.timer.stop()
# pwm.close()
# 初始化lvgl
lv.init()
-
# Register SDL display driver.
disp_buf1 = lv.disp_draw_buf_t()
buf1_1 = bytearray(LCD_SIZE_W * LCD_SIZE_H * 2)
-#buf1_2= bytearray(LCD_SIZE_W * LCD_SIZE_H * 2)
+buf1_2= bytearray(LCD_SIZE_W * LCD_SIZE_H * 2)
-disp_buf1.init(buf1_1, None, len(buf1_1))
+disp_buf1.init(buf1_1, buf1_2, len(buf1_1))
disp_drv = lv.disp_drv_t()
disp_drv.init()
disp_drv.draw_buf = disp_buf1
disp_drv.sw_rotate = True
disp_drv.rotated = 0#旋转角度0-3
disp_drv.register()
-
+# lv.init()
+# # Register SDL display driver.
+# disp_buf1 = lv.disp_draw_buf_t()
+# buf1_1 = bytearray(LCD_SIZE_W * LCD_SIZE_H * 2)
+# #buf1_2= bytearray(LCD_SIZE_W * LCD_SIZE_H * 2)
+
+# disp_buf1.init(buf1_1, None, len(buf1_1))
+# disp_drv = lv.disp_drv_t()
+# disp_drv.init()
+# disp_drv.draw_buf = disp_buf1
+# disp_drv.flush_cb = lcd.lcd_write
+# disp_drv.hor_res = LCD_SIZE_W
+# disp_drv.ver_res = LCD_SIZE_H
+# disp_drv.sw_rotate = True
+# disp_drv.rotated = 0#旋转角度0-3
+# disp_drv.register()
# LVGL触摸注册
lv.scr_load(power_on_screen)
utime.sleep_ms(200)
print("power_on_screen end...")
-PWM_backlight = PWM(PWM.PWM1, PWM.ABOVE_MS, 6, 10)
+PWM_backlight = PWM(PWM.PWM1, PWM.ABOVE_MS, 10, 10)
PWM_backlight.open()
device = mgr.DeviceInfoManager()
device.post_processor_after_instantiation()#订阅事件
+ light = mgr.getBrightnessManager()
+ light.post_processor_after_instantiation()
+
from ui_health import HealthScreen
import ui as _ui
-
+ import ai_alarm as _al
import ui_setting as _us
# import ui as _ui
EventMesh.debug_log("init4:{}".format(utime.localtime()))
ui.post_processor_after_instantiation()
app = watchApp()
app.set_ui(ui)
+ #创建闹钟类
+ al = _al.AI_alarm()
# if EventMesh.model == "D15":
# from motor import motorEventManager
# app.append_manager(motorEventManager())
ui.add_screen(_ui.PowerOnScreen())
ui.add_screen(_us.PoweroffConfirmScreen())
ui.add_screen(_ui.chargeInScreen()) #充电已连接
- ui.add_screen(_ui.chargefullScreen()) #充电已移出
+ ui.add_screen(_ui.chargefullScreen()) #充电已满
+ ui.add_screen(_ui.LowPowerScreen()) #电量低
+
+
except Exception as e:
usys.print_exception(e)
app.append_manager(_ai.device_res_author())
except Exception as e:
usys.print_exception(e)
-
+ #IOT
+ try:
+ import usr.protocol as pro
+ except Exception as e:
+ usys.print_exception(e)
+ import protocol as pro
+ try:
+ app.append_manager(pro.IOT_socket_SendCmdManager())
+ pcr = pro.ProtoColResolver()
+ pcr.add_support(pro.IOT_post_device_stateProtoCol())
+ pcr.add_support(pro.IOT_FindDeviceProtoCol())
+ # pcr.add_support(pro.IOTWeb_alarm_configProtoCol())
+ # pcr.add_support(pro.IOTWeb_alarm_listProtoCol())
+ sm = pro.SockMangager()
+
+ sm.add_support_resolver(pcr)
+ app.append_manager(sm)
+ print("init_IOT.0:{}".format(utime.localtime()))
+
+ except Exception as e:
+ usys.print_exception(e)
+ #endIOT
try:
-
app.append_manager(_ai.AI_VC())
except Exception as e:
usys.print_exception(e)
-
+ try:
+ EventMesh.publish("dmp_update")#dmp推送
+ except Exception as e:
+ usys.print_exception(e)
+ try:
+ EventMesh.publish("connect_iot_socket")#连接IOT
+ print("IOT连接成功")
+ except Exception as e:
+ usys.print_exception(e)
+ try:
+ EventMesh.publish("login_IOT")#登录IOT
+ EventMesh.publish("send_unbind_dev_to_iot")#开启IOT心跳包
+ except Exception as e:
+ usys.print_exception(e)
+
except Exception as e:
usys.print_exception(e)
EventMesh.publish("load_screen", {"screen": "poweron"})#开机画面
if battery[0] == "1":
if battery[1] >= 100:
if self.charge_full_count > 60 and self.charge_full_count % (60*10) == 0:#每十分钟提醒一次
- EventMesh.publish("load_screen", {"screen": "charge_full"})
+ # EventMesh.publish("load_screen", {"screen": "charge_full"})
+ pass
self.charge_full_count+=10
else:
self.charge_full_count = 0
class getBrightnessManager(Abstract):#获取亮度级别
def __init__(self):
- self.level = 6#默认值6
+ self.level = 10#默认值10最亮
# self.read_data = {}
self.time = 5
self.PWM_backlight = None
import request
import umqtt
import modem
+import versions
SHA256 = uhashlib.sha256
import SecureData
+import log
+import ustruct
+
def server_init(server_type = None):
#服务器选择1,防走丢,2大锤,3三基同创,4童信,5云米,6荣为 8:ds未知 dey.hinwatch. com:9968 9:183.62.239.121:31869 10:183.62.239.121:33461
if server_type == None:
client.error_register_cb(mqtterr_cb)
return client
+
+import uwebsocket
+import sim
-class SockManager(Abstract):
- def __init__(self):
- self.sock = None
- self.resolver = None
- self.run_flag = False
- self.lost_conn_check_time = 5 * 60 * 30
- self.monitor_timer = osTimer()
- self.publish_timer = osTimer()
- self.reconnect_timer = osTimer()
- self.mqtt_recv_timer = osTimer()
- self.reconnect_time = 1000
- self.reconnect_flag = 0
- self.connect_tmp = 0
- server_data = server_init()
- # EventMesh.debug_log("SockManager:server_data:{}".format(server_data))
- # self.server_addr = server_data[0]
- # self.server_port = server_data[1]
- self.server_addr = ""
- self.server_port = ""
- self.device_id = ""
- self.device_key = ""
- self.product_key = gewu_init()
- self.deviceSecret = ""
- self.client = 0
- self.client_dev = 0
- self.client_state = 0
- self.mqtt_client_count = 0
- ip_infor = {}
- ip_infor = EventMesh.publish("get_new_ip_com")
- EventMesh.debug_log("ip_infor1:{} \n\n\n".format(ip_infor))
-
- if ip_infor != None: #已经改过服务器
- self.server_addr = ip_infor[0]
- self.server_port = ip_infor[1]
- else:
- self.server_addr = server_data[0]
- self.server_port = server_data[1]
+class WEB_CMD_ENUM:
+ POST_DEVICE_STATE_R_CMD = "post_device_state_R"
+ POST_DEVICE_STATE_S_CMD = "post_device_state_S"
- EventMesh.debug_log("server_addr:{} server_port:{}".format(self.server_addr,self.server_port))
- _thread.stack_size((9+3)*1024)
- _thread.start_new_thread(self.connect, ())
- _thread.stack_size(8*1024)
-
-
- self.socket_send_queue = Queue()
- _thread.stack_size((9+2)*1024)
- _thread.start_new_thread(self.socket_send_queue_thread, ())
- _thread.stack_size(8*1024)
- EventMesh.subscribe("set_device_id",self.set_device_id)
- EventMesh.subscribe("set_device_key",self.set_device_key)
- EventMesh.subscribe("set_product_key",self.set_product_key)
+ POST_DEVICE_INFOR_R_CMD = "POST_DEVICE_INFOR_R_CMD"
+ POST_DEVICE_INFOR_S_CMD = "POST_DEVICE_INFOR_S_CMD"
- EventMesh.subscribe("get_device_id",self.get_device_id)
- EventMesh.subscribe("get_device_key",self.get_device_key)
- EventMesh.subscribe("get_product_key",self.get_product_key)
+ POST_ALARM_R_CMD = "post_alarm_R"
+ POST_ALARM_S_CMD = "post_alarm_S"
- EventMesh.subscribe("set_deviceSecret",self.set_deviceSecret)
+ FIND_DEVCE_R_CMD = "find_device_R"
+ FIND_DEVCE_S_CMD = "find_device_S"
- EventMesh.subscribe("get_deviceSecret",self.get_deviceSecret)
- if EventMesh.platform == "gewu":
- str = "deviceSecret:"
- buf = bytearray(32+len(str))
- length = SecureData.Read(2, buf, 32+len(str))
- deviceSecret = buf.decode()
- print(type(deviceSecret))
- if deviceSecret != "":
- if "deviceSecret" in deviceSecret:
- self.deviceSecret = deviceSecret.split(":")[1]
- else:
- self.deviceSecret = " "
- if EventMesh.platform == "gewu":
- self.client = mqtt_client_pro_init()
+ ALARM_CONFIG_R_CMD = "alarm_config_R"
+ ALARM_CONFIG_S_CMD = "alarm_config_S"
- def post_processor_after_instantiation(self):
- EventMesh.subscribe("get_mqtt_pro_connect_state",self.get_mqtt_pro_connect_state)
- EventMesh.subscribe("get_mqtt_dev_connect_state",self.get_mqtt_dev_connect_state)
- EventMesh.subscribe(constants.EVENT.CHANNEL_SOCKET_SEND, self.send)
- self.monitor_timer.start(7 * 60 * 1000, 1, self.check)
+ ALARM_LIST_R_CMD = "alarm_list_R"
+ ALARM_LIST_S_CMD = "alarm_list_S"
- def add_support_resolver(self, resolver):
- self.resolver = resolver
+ UNBIND_DEV_R="unbind_dev_R"
+ UNBIND_DEV_S="unbind_dev_S"
- def initialization(self, *args, **kwargs):
- _thread.stack_size(16*1024)
- _thread.start_new_thread(self.recv, ())
- _thread.stack_size(8*1024)
-
- def set_device_id(self,event,msg):
- self.device_id = str(msg)
+ DEVICE_SHAKE_STATE_R_CMD = "device_shake_state_R"
+ DEVICE_SHAKE_STATE_S_CMD = "device_shake_state_S"
+
+class IOT_socket_SendCmdManager(Abstract):
+ #
+ def __init__(self):
+ self.send_data = ""
+ self.time_tmp = 0
+ def post_processor_after_instantiation(self):
+ EventMesh.subscribe("GET_IOT_SEND_CMD", self.get_iot_send_cmd)
+ print("IOTSendCmdManager")
+ #调用:device_state=EventMesh.publish("GET_IOT_SEND_CMD",WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD)
+ # print("device_state{}".format(device_state))
+ def get_iot_send_cmd(self, event, msg):#获取准备发送的值
+ date_tmp = utime.localtime()
+ self.time_tmp = utime.mktime(date_tmp)
+ if msg == WEB_CMD_ENUM.POST_DEVICE_STATE_S_CMD:#设备VC状态
+ self.send_data = self.device_report_state_send_data()
+ return self.send_data
+ elif msg == WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD:#设备信息
+ self.send_data = self.device_information_send_data()
+ return self.send_data
+ elif msg == WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD:#聊天内容
+ self.send_data = self.device_information_send_data()
+ return self.send_data
- def get_device_id(self,event,msg):
+ # 设备对话内容上报数据格式
+ def device_talk_send_data(self):
+ print("device_talk_send_data")
+ infor_send_data = {
+ "cmd":"chat_text",
+ "data":
+ {
+ "device_id":modem.getDevImei(),#设备号
+ "type":"req:请求说的话;res:响应的内容",
+ "text":"用户说话内容",
+ "createTime":"时间戳"
+ }
+ }
+ return infor_send_data
+
+ # 设备信息上报数据格式
+ def device_information_send_data(self):
+ print("device_information_send_data")
+ battery_state = (EventMesh.publish("screen_get_battery"))[0]
+ battery = (EventMesh.publish("screen_get_battery"))[1]
+ if battery >= 100 or battery == None:
+ battery = 100
+ VC_TTS_volume = EventMesh.publish("get_storage_config","VC_TTS_volume")#音量配置
+ if VC_TTS_volume == None:
+ VC_TTS_volume =100
+ sourceVersion =versions.Build_Time
+ Timeversion ="JSWM-"+sourceVersion
+ infor_send_data = {
+ "data":{
+ "version":Timeversion,#版本号
+ "charge":battery_state,#0表示未充电,1表示充电中
+ "current_role_name":"",#当前音色的name
+ "volume":str(VC_TTS_volume),#百分比数值
+ "wifi_rssi":str(net.csqQueryPoll()//6),#wifi强弱:0,1,2,3,4,5。转成这几个梯度
+ "battery":str(battery),#电量
+ "device_id":modem.getDevImei(),#设备号
+ },
+ "cmd":"device_info"
+ }
+ return infor_send_data
+
+ #设备上报VC状态
+ def device_report_state_send_data(self):
+ ai_status = EventMesh.publish("screen_get_ai")
+ if EventMesh.publish("get_VC_satrt_flag") == 1:#获取vc是否在运行
+ if ai_status < 6 :
+ target_status = "listening"
+ elif ai_status == 6:
+ target_status = "thinking"
+ elif ai_status >= 8:
+ target_status = "speaking"
+ else:
+ target_status = "idle"
+
+ device_report_data ={
+ "data":{
+ "device_id":modem.getDevImei(),
+ "state":target_status
+ },
+ "cmd":"chat_state"
+ }
+ return device_report_data
+def extract_target_number(json_str):
+ # 查找"target":"的起始位置
+ start_key = '"target":"'
+ start_idx = json_str.find(start_key)
+ if start_idx == -1:
+ print("未找到 target 字段")
+ return None # 未找到目标字段
+
+ # 计算数字的起始位置(跳过"target":")
+ num_start = start_idx + len(start_key)
+
+ # 从数字起始位置开始,查找结束的双引号(")
+ num_end = json_str.find('"', num_start)
+ if num_end == -1:
+ print("未找到数字的结束位置")
+ return None # 格式异常
+
+ # 截取数字字符串(从num_start到num_end)
+ number_str = json_str[num_start:num_end]
+
+ # 转换为整数(如果需要浮点数,可改为float(number_str))
+ try:
+ return int(number_str)
+ except ValueError:
+ print("截取的内容不是有效数字")
+ return None
+
+def playload_data(data):
+ print("data = {}".format(data))
+ if isinstance(data, bytes) == 0 :
+ print("data类型错误")
+ return
- return self.device_id
- def set_device_key(self,event,msg):
- self.device_key = str(msg)
+ if data[0] != 0xff or data[1] !=0xfe:
+ print("data格式错误,重新登录")
+ EventMesh.publish("login_IOT")#登录IOT
return
- def get_device_key(self,event,msg):
+ payload_len_bytes = data [3:5]
+ payload_len = ustruct.unpack ('H', payload_len_bytes)[0]
+ # print ("解析到 Payload 长度:{} 字节".format(payload_len))
+
+ payload = data [5 : 5+ payload_len]
+ try:
+ json_str = payload.decode ('utf-8')
+ except UnicodeDecodeError:
+ try:
+ json_str = payload.decode ('gbk')
+ print ("提示:Payload 使用 GBK 编码")
+ except UnicodeDecodeError:
+ print ("Payload 解码失败")
+ return
+ # json_str = "\"" + json_str + "\""
+ if type(json_str) is str and len(json_str)>5:
+ print ("解析出的 JSON 字符串:{}".format(json_str) + "-"*50)
+ if "get_device_state" in json_str:
+ EventMesh.publish("send_device_information")#发送设备信息
+ EventMesh.publish("send_device_VC_state")#上传VC状态
+ print("get_device_state")
+ elif "find_device" in json_str:
+ EventMesh.publish("play_tts_single","我在这呀,我在这呀")
+ print("find_device")
+ elif "renew_device" in json_str:#更新对话模式 重启
+ EventMesh.publish("play_tts_single","更新配置中,设备将自动重启")
+ print("renew_device")
+ utime.sleep_ms(3000)
+ EventMesh.publish("Power_off")
+ elif "switch_volume" in json_str:
+ volume = int(extract_target_number(json_str))
+ print("switch_volume = {}".format(volume))
+ EventMesh.publish("update_volume",volume)
+ elif "switch_brightness" in json_str:
+ light = int(extract_target_number(json_str))//10
+ print("switch_brightness")
+ EventMesh.publish("set_brightness_level",light)
+ elif "setup_role" in json_str:
+ EventMesh.publish("play_tts_open","角色正在切换")
+ print("setup_role")
+ EventMesh.publish("load_screen", {"screen": "UI_ai"})#ai画面
- return self.device_key
-
- def set_product_key(self,event,msg):
- self.product_key = str(msg)
- def get_product_key(self,event,msg):
+ # data_dict = ujson.loads(json_str)
+ # if isinstance(data_dict, dict):
+ # #下面做小程序下发指令类型判断
+ # data = data_dict["cmd"]
+ # if data is "get_device_state":
+ # EventMesh.publish("send_device_information")#发送设备信息
+ # print("get_device_state")
+ # elif data is "find_device":
+ # EventMesh.publish("play_tts_single","我在这呀,我在这呀")
+ # print("find_device")
+ # else:
+ # print("JSON数据不是字典类型")
- return self.product_key
- def set_deviceSecret(self,event,msg):
- if EventMesh.platform == "gewu":
- self.deviceSecret = str(msg)
- deviceSecret_tmp = "deviceSecret:{}".format(msg)
- SecureData.Store(2, deviceSecret_tmp, len(deviceSecret_tmp))
-
- def get_deviceSecret(self,event,msg):
- return self.deviceSecret
+
+date_tmp = utime.localtime()
+time_tmp = utime.mktime(date_tmp)
+MAGIC = (0xfffe).to_bytes(2,"big")
+VERSION = (0x01).to_bytes(1,"big")#"03".encode('utf-8')
+TYPE = (0x03).to_bytes(1,"big")
+DATA_LEN = (0x00000000).to_bytes(4,"big")
+#magic+version+type+playload_len+playload
+def protocol_send_total_data(data):
+ MAGIC = (0xfffe).to_bytes(2,"big")
+ VERSION = (0x01).to_bytes(1,"big")#"03".encode('utf-8')
+ TYPE = (0x03).to_bytes(1,"big")
+ HR_JSON = ujson.dumps(data)
+ GPS_JSON_b = HR_JSON.encode('utf-8')
+ DATA_LEN = (len(HR_JSON)).to_bytes(4,"big")
+ heards_infor = b''
+ heards_infor = MAGIC+VERSION+TYPE+DATA_LEN+GPS_JSON_b
+ return heards_infor
+
+DEFIEN_HR_REPORT_TIME = 5*60
+DEFINE_TIME_COUNT = 5
+DEFIEN_LOCATION_REPORT_TIME = 5
+WEB_CONNECT_MAX_COUNT = 10 #默认重连次数
+
+PROJECT_NAME = "JSWM"
+PROJECT_VERSION = "1.0.0"
+checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION)
+# 设置日志输出级别
+log.basicConfig(level=log.INFO)
+socket_log = log.getLogger("SOCKET")
+class SockMangager(Abstract):
+ def __init__(self):
+ self.thread_buf_size = 8*1024
+ self.iot_soc_send_queue = Queue(100)
+ self.iot_protoclo_recv_id=None
+ self.connect_timer = osTimer()
+ self.connect_timer_count = 0
+ self.hr_report_timer = osTimer()
+ self.resolver = None
+ self.send_device_time = 0
+ self.vbat_buf = []
+ self.network_state = 0
+ self.socket_send_queue_id = None
+ self.bat_count = 0
+ self.reconnect_count = 0 #连续重连次数 默认十次 不过就不重连了 等下一个心跳重连
+ self._1S_timer = osTimer()
+ self._5S_timer = osTimer()
+ self.timer_id = 0
+ self.start_voice_flag = 0
+ self.IOT_sock = None
+ self.sock_lock = _thread.allocate_lock() # 初始化锁
+ #对话状态,一秒检查一次
+ self.last_data = None # 保存上一次的数据状态
+ self.current_data = None # 当前数据
+
+ self.send_recv_flag = 0#线程开启状态
+ EventMesh.subscribe("REPORT_ALARM_TO_IOT",self.report_alarm_to_iot)
+
+ def report_alarm_to_iot(self,event,msg):
+ EventMesh.publish(WEB_CMD_ENUM.POST_ALARM_S_CMD,msg)
+ pass
+ def usb_event_cb(self, state):
+ status = state
+ def post_processor_after_instantiation(self):
+ EventMesh.subscribe("CHANNEL_IOT_SEND",self.user_send)#发送数据的函数!!重要
+ EventMesh.subscribe("GET_IOT_PROTOCOL_CILENT",self.get_IOT_sock)
+ EventMesh.subscribe("close_socket_timer",self.close_socket_timer)
+ EventMesh.subscribe("connect_iot_socket",self.connect_iot_socket_cb)#使用socket连接iot平台
+ EventMesh.subscribe("login_IOT",self.login_IOT)#登录iot平台
+ EventMesh.subscribe("heart_IOT",self.heart_IOt)#心跳包
+ EventMesh.subscribe("send_device_information",self.send_device_information)#上报设备信息
+ EventMesh.subscribe("send_device_VC_state",self.send_device_VC_state)#上报VC状态
+ EventMesh.subscribe("send_unbind_dev_to_iot",self.send_unbind_dev_to_iot)#心跳包定时器开启
+ self.reconnect_count = 0
+ self.deviceReadState = ""
+ # self.connect_timer.start(2000,0,self.iot_connect_timerCb)
+
+ def send_device_information(self,event,msg):
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.send_packet_iot,"data":WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD})#上报设备信息
+ def send_device_VC_state(self,event,msg):
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.send_packet_iot,"data":WEB_CMD_ENUM.POST_DEVICE_STATE_S_CMD})#上报VC状态
+
+ def send_unbind_dev_to_iot(self,event,msg):
+ self._5S_timer.start(30000,1,self._1M_timer_cb)
+ self._1S_timer.start(1000,1,self._1S_timer_cb)
+ def _1M_timer_cb(self,*argc):
+ EventMesh.publish("heart_IOT")#开启IOT心跳包
+ EventMesh.publish("send_device_information")#发送设备信息
+ pass
- def connect(self):
- EventMesh.debug_log("connect1{}:{}".format(self.server_addr, self.server_port))
- if EventMesh.publish("get_sim_Status") != 1: #没sim
- return
- try:
- if(self.sock != None) :
- self.sock.close()
- self.sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
- #self.sock.setblocking(False) &self.sock.settimeout(0)不阻塞
- self.sock.connect((self.server_addr, self.server_port))
-
- self.publish_timer.start(2000, 1, self.publish_timer_cb)
- if EventMesh.platform == "gewu":
- self.mqtt_client_count = 0
- self.mqtt_recv_timer.start(5000, 1, self.mqtt_recv_timer_cb)
-
- utime.sleep_ms(500)
- EventMesh.publish(constants.PROTOCOL.LK_SEND)
- # 发送数据
-
-
- except Exception as e:
- usys.print_exception(e)
- self.run_flag = False
+ def initialization(self, *args):
+ pass
+ def connect_iot_socket_cb(self,event,msg):
+ self.connect_iot_socket()
+ def add_support_resolver(self, resolver):
+ self.resolver = resolver
+ def hr_report_event(self, *args, **kwargs):
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.hr_report_event_cb}) #self.connect_iot_websocket()
+ def hr_report_event_cb(self):
+ """电池平均值"""
+ temp = Power.getVbatt()
+ if self.bat_count < 10:
+ self.vbat_buf.append(temp)
+ self.bat_count += 1
else:
- self.run_flag = True
- EventMesh.debug_log("connect2{}:{}".format(self.server_addr, self.server_port))
- self.reconnect_flag = 0
- def publish_timer_cb(self, *args):
- self.authen_set()
-
- def authen_set(self):
- sever_state = EventMesh.publish("get_server_state")#获取修改服务器状态
- # print("sever_state{}".format(sever_state))
- if sever_state != None:
- if sever_state == 0:
- imei = EventMesh.publish(constants.EVENT.GET_IMEI)
- server_data = EventMesh.publish("get_new_key_pid")#获取pid和key
- key_data = ""
- pid_data = ""
- if server_data != None:
- key_data = server_data[0]
- pid_data = server_data[1]
- else:
- server_data = server_init()
- key_data = server_data[2]
- pid_data = server_data[3]
-
- # server_data = server_init()
- # key_data = server_data[2]
- # pid_data = server_data[3]
-
- sonce_data = str(urandom.getrandbits(32))#随机生成32位的随机数
- md5_data = "{}*{}*{}*{}".format(imei,pid_data,sonce_data,key_data)#md5签名
- sign_data = ""
- hash_obj = uhashlib.md5(md5_data)
- res = hash_obj.digest()
-
- # 转成十六进制表示
- sign_data = ubinascii.hexlify(res)
- sign_data = sign_data.decode('ascii')
- # print("sign_data:{} sonce_data:{}".format(md5_data,sign_data))
- # sign_data = MD5_head
- # http://8.134.110.49:31379/dev/device/check?imei=&bid=sonce=sign=
- # ip_addr = "test.iot.api.thisiot.com"
- # ip_addr = "app.api.thisiot.com"
- # http://app.api.thisiot.com/
- url = "http://app.api.thisiot.com/dev/device/check?imei={}&bid={}&sonce={}&sign={}".format(imei,pid_data,sonce_data,sign_data)
-
- # print("url:{}".format(url))
- response = request.get(url)
- data_tmp ={}
- # d_server_addr = "device.miwitracker.com"
- # d_server_port = 8505
- # d_md5_key = ""
- # d_PID = "3G"
- # response.content = {'protocolType': '', 'host': 'device.miwitracker.com', 'secretKey': '', 'port': 8505, 'bid': '3G', 'extJsonStr': ''}
- # response.status_code=200
- print("test-{}".format(response.status_code))
- if response.status_code == 200:
- content = response.content
- c = next(content)
- # "api.xcloudtech.com"
- # d_server_port = 9000
- jsload_data = ujson.loads(c)
- print("jsload_data-{}".format(jsload_data))
- # jsload_data = {'data':'111','protocolType':'', 'host':'device.miwitracker.com', 'secretKey': 'bZld0ALsZTt15tKEZhOlLPgbsO75BLTP', 'port':8505, 'bid': '3G', 'extJsonStr': ''}
- # ujson.loads(c)
-
- if "success" in jsload_data:
- success = jsload_data["success"]
- if success == True:#合法设备
- if "data" in jsload_data:
- data_tmp = jsload_data["data"]#返回的数据
- print("data_tmp:{}".format(data_tmp))
- code = jsload_data["code"]
- if code == 20000:#合法的设备
- protocloType = data_tmp["protocolType"]#协议类型
- host = data_tmp["host"]#服务骑地址
- secretKey = data_tmp["secretKey"]#
- pid = data_tmp["bid"]#产品型号
- port = data_tmp["port"]#端口号
-
-
-
- if host != '' and (port != '' and port != -1):
- if host != '':
- self.server_addr = host
- EventMesh.publish("set_ip",str(self.server_addr))
-
- if port != '' and port != -1:
- self.server_port = port
- EventMesh.publish("set_com",self.server_port)
- EventMesh.publish("set_new_key", str(secretKey))#获取pid和key
- EventMesh.publish("set_new_pid",str(pid))#获取pid和key
- # self.reconnect_timer_cb()#重连设备
- print("self.reconnect_flag",self.reconnect_flag)
- self.reconnect_flag = 0
- self.reconnect()#重连设备
- self.publish_timer.stop()
- EventMesh.publish("set_server_state",1)#获取修改服务器状态
- else:
- self.publish_timer.stop()
-
-
-
- def mqtt_recv_timer_cb(self, *args):
- self.mqtt_clien_cb()
+ for i in range(9):
+ self.vbat_buf[i] = self.vbat_buf[i+1]
+ self.vbat_buf[9] = temp
+ curr_count = len(self.vbat_buf)
+ bat_total_value = 0
+ for i in range(curr_count):
+ bat_total_value += self.vbat_buf[i]
+ bat_total_value = bat_total_value//curr_count#一分钟更新一次电量 10个平均值
+ EventMesh.publish("AI_alarm_start") #检查是否有闹钟需要提醒
+ # self.alarm_test()
+ EventMesh.publish("set_curr_battery_level",bat_total_value)
+ # EventMesh.publish("publish_AI_btnInfo",{"func":self.hr_report_publish_event,"data":0})
+ if self.send_device_time < DEFIEN_LOCATION_REPORT_TIME :
+ self.send_device_time+=DEFINE_TIME_COUNT
+ else:
+ device_state=EventMesh.publish("GET_IOT_SEND_CMD",WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD)
+ print("device_information{}".format(device_state))
+ # EventMesh.publish(WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD,device_state) #上报设备信息
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.send_packet_iot,"data":WEB_CMD_ENUM.POST_DEVICE_INFOR_S_CMD})#上报设备信息
+
+ def iot_connect_timerCb(self,*argc):
+ self.connect_iot_socket()
+
+ def connect_iot_socket(self):
+ if EventMesh.publish("get_voice_record_flag") == 1:
+ EventMesh.publish("stop_voice_record")
+ print("connect_iot_socket !!!!")
+ # self.iot_close_therad()
+ stagecode, subcode = checknet.wait_network_connected(30)
+ if stagecode == 3 and subcode == 1:
+ socket_log.info('Network connection successful!')
-
- def mqtt_clien_cb(self):
- if EventMesh.platform != "gewu":
+ if self.reconnect_count >= WEB_CONNECT_MAX_COUNT: #重连次数大于10次不在进重连只有下发心跳才重新连接
return
- # 需要加密的数据
- get_deviceSecret = EventMesh.publish("get_deviceSecret")
- if get_deviceSecret != None:
- if self.mqtt_client_count == 0:
- self.mqtt_client_count = 1
- self.mqtt_recv_timer.stop()
- get_deviceSecret = EventMesh.publish("get_deviceSecret")#获取设备的秘钥 只获取一次
- print("get_deviceSecret{}".format(get_deviceSecret))
- if get_deviceSecret == '':#如果为空就获取一次
- # print("self.client:{}".format(self.client))
- mqtt_connect = -1
- try:
- mqtt_connect = self.client.connect()
- except Exception as e:
- print(e)
- mqtt_connect = -1
- print("mqtt_connect:{}".format(mqtt_connect))
- if mqtt_connect == 0 :
- # 订阅主题
- get_device_id = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_deviceKey = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_productKey = gewu_init()
- #$sys/{productKey}/{deviceKey}/ext/regist
- client_msg = "$sys/{}/{}/ext/regist".format(get_productKey,get_deviceKey)
- # client_msg = "$sys/cu1shld45y4hjr1L/866610001011658/ext/regist"
- subscribe_msg = client_msg.encode('ascii')
- print(subscribe_msg)
-
- self.client.subscribe(subscribe_msg,0)#订阅消息主题
-
-
- self.client.wait_msg() # 阻塞函数,监听消息
- utime.sleep(5)
- get_deviceSecret = EventMesh.publish("get_deviceSecret")
- if get_deviceSecret != '':
- self.client.disconnect()
- self.client_dev = mqtt_client_dev_init()
- print(self.client_dev)
- # mqtt_connect = self.client_dev.connect()
- try:
- mqtt_connect = self.client_dev.connect()
- except Exception as e:
- print(e)
- mqtt_connect = -1
- if mqtt_connect == 0:
- # $sys/cu1shld45y4hjr1L/bOOSGN5FlXEjt15/property/batch_reply
- msg_reply = "$sys/{}/{}/property/batch_reply".format(get_productKey,get_deviceKey)
- sub_msg = msg_reply.encode('ascii')
- self.client_dev.subscribe(sub_msg,0)#订阅消息主题
- print("Connected to dmp-mqtt.cuiot.cn, subscribed to /public/TEST/quecpython topic")
- # 发布消息
- # UnicodeHexStr_To_Utf8Str(str_data)
- date_tmp = utime.localtime()
- time_tmp = utime.mktime(date_tmp)#需要转换成毫秒级别
- updataTime = "{}".format(time_tmp*1000)
- # imei_tmp= modem.getDevImei()
- imei_tmp = EventMesh.publish(constants.EVENT.GET_IMEI)
- bat_tmp = EventMesh.publish("screen_get_battery")
- imei = "{}".format(imei_tmp)
- power = 0
- power = int(bat_tmp[1])
- hr = 0
- hr = EventMesh.publish("get_old_hr_data")
- if hr == None:
- hr = 0
- deviceTime = "{}".format(time_tmp)
- manufactury = "fengda"
- DeviceState = "online"
-
- data_info = {
- "messageId":"0",
- "params": {
- "data": [
- {
- "key":"deviceOffOn",
- "value": {
- "deviceStatus":"Poweron",
- "updateTime":updataTime,
- "Imei":imei
- }
-
- },
- {
- "key":"HeartRate",
- "value":{
- "heartRate":hr,
- "updateTme":updataTime,
- "Imei":imei
- }
- },
- {
- "key":"powerSavingMode",
- "value":0
- },
- {
- "key":"IMEI",
- "value":imei
- },
- {
- "key":"DEVICE_TIME",
- "value":deviceTime
- },
- {
- "key":"MANUFACTURER",
- "value":manufactury
- },
- {
- "key":"REMAINING_POWER",
- "value":power
- },
- {
- "key":"DeviceState",
- "value":DeviceState
- }
- ]
- }
- }
-
- data_json = ujson.dumps(data_info)
- # print("data_json:{}",data_json)
- # $sys/cu1shld45y4hjr1L/{deviceKey}/property/batch
- msg_pub = "$sys/{}/{}/property/batch".format(get_productKey,get_deviceKey)
- pub_msg = msg_pub.encode('ascii')
- self.client_dev.publish(pub_msg,data_json,0)#publis主题内容
-
- print("Publish topic: /public/TEST/quecpython758, msg: my name is Quecpython")
- pass
+ token = EventMesh.publish("get_dev_token")
+ # token = "9548860f973bffe39e1679db3110e223cb"
+ print("token:{}".format(token))
+ if self.IOT_sock is not None:
+ print("socket已连接")
+ return
+ try:
+ if token != None:
+ self.connect_timer_count = 0
+ #创建一个socket实例
+ self.IOT_sock = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
+ try:
+ #建立连接
+ self.IOT_sock.connect(('iot.socket.thisiot.com', 7777))
+ #设置为阻塞
+ self.IOT_sock.setblocking(True)
+ socket_log.info("IOT 连接建立")
+ except Exception as e:
+ print("再次连接")
+ self.IOT_sock.connect(('iot.socket.thisiot.com', 7777))
+ #设置为非阻塞
+ self.IOT_sock.setblocking(False)
+
+ if self.send_recv_flag == 0:#线程未开启过
+ self.send_recv_flag = 1
+ self.reconnect_count = 0
+ _thread.stack_size(self.thread_buf_size+8*1024) #_thread.stack_size(16*1024)
+ self.socket_send_queue_id = _thread.start_new_thread(self.socket_send_queue_thread, ())
+ _thread.stack_size(8*1024)
+
+ _thread.stack_size(self.thread_buf_size+8*1024)
+ self.iot_protoclo_recv_id = _thread.start_new_thread(self.iot_protocol_recv, ())
+ _thread.stack_size(8*1024)
+ socket_log.info("self.IOT_sock thread init!!!!!!!!!")
+
+ if self.IOT_sock != None:
+ self.start_voice_flag = 1
else:
- mqtt_dev_connect = -1
- mqtt_ret_connect = -1
- mqtt_pro_connect = -1
- if self.client_dev == 0:
- self.client_dev = mqtt_client_dev_init()
- try:
- mqtt_dev_connect = self.client_dev.connect()
- except Exception as e:
- print("erro!{}".format(e))
- mqtt_dev_connect = -2
- # Server Actively FIN Disconnected.Need Check Connection parameters
- err_dis = "FIN Disconnected" in str(e)
- err_parm1 = "107" in str(e)
- err_parm2 = "4" in str(e)
- # print("err_parm1!{} {} {} {}".format(err_parm1,err_parm2,err_info,err_dis))
- # Connect Error='4' MQTT Connect error=
- if err_dis == True or err_parm1 == True or err_parm2 == True:
- mqtt_dev_connect = -1
-
-
- if mqtt_dev_connect != 0:#连接参数错误可能是deviceScrete出错重新获取
+ self.start_voice_flag = 0
- try:
- mqtt_ret_connect = self.client.connect()#重新获取deviceScrete
- except Exception as e:
- print(e)
- mqtt_ret_connect = -1
- # mqtt_connect = self.client.connect()
- print("mqtt_ret_connect:{}".format(mqtt_ret_connect))
- if mqtt_ret_connect == 0:
- # 订阅主题
- get_device_id = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_deviceKey = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_productKey = gewu_init()
- #$sys/{productKey}/{deviceKey}/ext/regist
- client_msg = "$sys/{}/{}/ext/regist".format(get_productKey,get_deviceKey)
- # client_msg = "$sys/cu1shld45y4hjr1L/866610001011658/ext/regist"
- subscribe_msg = client_msg.encode('ascii')
- print(subscribe_msg)
-
- self.client.subscribe(subscribe_msg,0)#订阅消息主题
-
- self.client.wait_msg() # 阻塞函数,监听消息
- utime.sleep(5)
-
- self.client.disconnect()
- self.client_dev = mqtt_client_dev_init()
- # print(self.client_dev)
- try:
- mqtt_pro_connect = self.client_dev.connect()
- except Exception as e:
- print(e)
- mqtt_pro_connect = -1
- # print("no deviceScret!!!!!!!{}".format(self.client_dev))
- # 设备秘钥不为空 重连获取设备失败不连接 第一次连接失败不连接不发送数据
- if EventMesh.publish("get_deviceSecret") != "" and (mqtt_pro_connect == 0 or mqtt_dev_connect == 0):
- get_device_id = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_deviceKey = EventMesh.publish(constants.EVENT.GET_IMEI)
- get_productKey = gewu_init()
- # $sys/cu1shld45y4hjr1L/bOOSGN5FlXEjt15/property/batch_reply
- msg_reply = "$sys/{}/{}/property/batch_reply".format(get_productKey,get_deviceKey)
- sub_msg = msg_reply.encode('ascii')
- # print(" deviceScret!!!!!!!{} msg_reply:{} sub_msg:{}".format(self.client_dev,msg_reply,sub_msg))
- self.client_dev.subscribe(sub_msg,0)#订阅消息主题
- print("Connected to dmp-mqtt.cuiot.cn, subscribed to /public/TEST/quecpython topic")
- # 发布消息
- # UnicodeHexStr_To_Utf8Str(str_data)
- date_tmp = utime.localtime()
- time_tmp = utime.mktime(date_tmp)#需要转换成毫秒级别
- updataTime = "{}".format(time_tmp*1000)
- imei_tmp = EventMesh.publish(constants.EVENT.GET_IMEI)
- imei = "{}".format(imei_tmp)
- bat_tmp = EventMesh.publish("screen_get_battery")
- power = 0
- power = int(bat_tmp[1])
- hr = 0
- hr = EventMesh.publish("get_old_hr_data")
- if hr == None:
- hr = 0
- deviceTime = "{}".format(time_tmp)
- manufactury = "fengda"
- DeviceState = "online"
-
- data_info = {
- "messageId":"0",
- "params": {
- "data": [
- {
- "key":"deviceOffOn",
- "value": {
- "deviceStatus":"Poweron",
- "updateTime":updataTime,
- "Imei":imei
- }
-
- },
- {
- "key":"HeartRate",
- "value":{
- "heartRate":hr,
- "updateTme":updataTime,
- "Imei":imei
- }
- },
- {
- "key":"powerSavingMode",
- "value":0
- },
- {
- "key":"IMEI",
- "value":imei
- },
- {
- "key":"DEVICE_TIME",
- "value":deviceTime
- },
- {
- "key":"MANUFACTURER",
- "value":manufactury
- },
- {
- "key":"REMAINING_POWER",
- "value":power
- },
- {
- "key":"DeviceState",
- "value":DeviceState
- }
- ]
- }
- }
-
- data_json = ujson.dumps(data_info)
- # print("data_json:{}",data_json)
- # $sys/cu1shld45y4hjr1L/{deviceKey}/property/batch
- msg_pub = "$sys/{}/{}/property/batch".format(get_productKey,get_deviceKey)
- pub_msg = msg_pub.encode('ascii')
- self.client_dev.publish(pub_msg,data_json,0)#publis主题内容
-
- print("Publish topic: /public/TEST/quecpython758, msg: my name is Quecpython")
-
- def get_mqtt_pro_connect_state(self,event,msg):
- return self.client
- def get_mqtt_dev_connect_state(self,event,msg):
- return self.client_dev
-
- def check(self, *args):
- if (not self.run_flag) or (self.connect_tmp == 0) : #7分钟无数据读取,则认为是掉线了
- EventMesh.debug_log("tcp reconnect!!!!!!!!!!!!!!!!!!")
- EventMesh.publish(constants.EVENT.SET_CONNECT,0) #标记断网
- self.reconnect()
- self.connect_tmp = 0
- def reconnect(self):
- if(self.reconnect_flag == 1):
- return
- self.reconnect_flag = 1
- self.reconnect_timer.start(self.reconnect_time, 0, self.reconnect_timer_cb)
- if self.reconnect_time < 600*1000:
- self.reconnect_time += 30*1000
-
- def reconnect_timer_cb(self, *args):
- _thread.stack_size((9+1)*1024)
- _thread.start_new_thread(self.connect, ())
- _thread.stack_size(8*1024)
+ print("self.IOT_sock {} self.start_voice_flag:{}".format(self.IOT_sock,self.start_voice_flag))
+ if self.IOT_sock != None:
+ if self.timer_id == 0:
+ # self.hr_report_timer.start(DEFINE_TIME_COUNT*1000, 1, self.hr_report_event)
+ self.timer_id=1
+ else:
+ print("没有token!!!!!!!!!!")
+ self.connect_timer_count+=1
+ if self.connect_timer_count <= 10:
+ print("IOT重连定时器开启")
+ self.connect_timer.start(5000,0,self.iot_connect_timerCb)
+ pass
+ except Exception as e:
+ self.IOT_sock = None
+ print("connect_iot_socket error")
+ def heart_IOt(self,event,msg):
+ print("heart_IOT.....")
+ #Header
+ header = ustruct.pack('>H', 0xFFFE) # 使用大端模式
+ #Type
+ packet_type = ustruct.pack('B', 0x02)
+ #拼接
+ heart_packet = header + packet_type
+ EventMesh.publish("CHANNEL_IOT_SEND", heart_packet)
+ # print("心跳发送数据包:{}".format(heart_packet))
+
+ def send_packet_iot(self,data):#发送数据给iot,data为接口json数据
+ #Header
+ header = ustruct.pack('>H', 0xFFFE) # 使用大端模式
+ #Type
+ packet_type = ustruct.pack('B', 0x03)
+ #字典转为json字符串
+ json_str = EventMesh.publish("GET_IOT_SEND_CMD", data)
+ json_str = ujson.dumps(json_str)
+ #字符串转为二进制数据Payload
+ payload = json_str.encode('utf-8')
+ #PayloadLen
+ payloadLen = ustruct.pack('H', len(payload))
+ #CRC16(2字节,基于pay字段计算)
+ crc = self.crc16(payload)
+ print("crc的长度为{}".format(len(crc)))
+ #拼接
+ full_packet = header + packet_type + payloadLen + payload+ crc
+ EventMesh.publish("CHANNEL_IOT_SEND", full_packet)
+ print("发送更新数据包:{}".format(full_packet))
+
+ def login_IOT(self,event,msg):
+ print("登录中")
+ #Header
+ header = ustruct.pack('>H', 0xFFFE) # 使用大端模式
+ #Type
+ packet_type = ustruct.pack('B', 0x00)
+ #设备ID
+ device_id_bytes = modem.getDevImei().encode('utf-8')[:20] # 转为字节并截断到20字节
+ device_id = bytes_ljust(device_id_bytes, 20, b'\x00')
+ #令牌
+ token_bytes = EventMesh.publish("get_dev_token").encode('utf-8')[:36] # 转为字节并截断
+ token_padded = bytes_ljust(token_bytes, 36, b'\x00')
+ #拼接
+ body = header + packet_type + device_id + token_padded
+ #CRC16(2字节,基于上述所有字段计算)
+ crc = self.crc16(body)
+ # 完整数据包
+ full_packet = body + crc
+ EventMesh.publish("CHANNEL_IOT_SEND", full_packet)
+ print("登录发送数据包:{}".format(full_packet))
+
+
+ def crc16(self, data):
+ """计算CRC16校验值(MODBUS RTU模式)"""
+ crc = 0xFFFF
+ for byte in data:
+ crc ^= byte
+ for _ in range(8):
+ if crc & 0x0001:
+ crc >>= 1
+ crc ^= 0xA001
+ else:
+ crc >>= 1
+ # 返回2字节小端模式
+ return ustruct.pack('<H', crc & 0xFFFF)
+ def close_socket_timer(self,event,msg):
+ self._1S_timer.stop()
+ self._5S_timer.stop()
+
+ def _1S_timer_cb(self,*argc):
+ self.current_data = EventMesh.publish("screen_get_ai") # 当前数据
+ if self.current_data is not self.last_data :
+ print("VC状态改变")
+ EventMesh.publish("send_device_VC_state")#上传VC状态
+ self.last_data = self.current_data # 保存上一次的数据状态
+
def socket_send_queue_thread(self):
while True:
- data = self.socket_send_queue.get()
- EventMesh.debug_log("TCP:send data1 len:{}".format(len(data)))
-
- #EventMesh.debug_log("ui_queue_thread:data = {}".format(data))
- socketsta = self.sock.getsocketsta()
- if(socketsta == -1): #给释放了或者出错了
- continue
- if(socketsta == 4):#正常连击
+ # with self.sock_lock: # 操作Socket前加锁
+ data = self.iot_soc_send_queue.get()
if data != None:
- try:
- self.sock.send(data)
- EventMesh.debug_log("TCP:send data2 len:{}".format(len(data)))
+ try:
+ if self.IOT_sock is not None:
+ self.IOT_sock.send(data)
+ # EventMesh.debug_log("发送线程")
+ self.reconnect_count = 0
+ else:
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
+ # print("socket关闭退出send线程")
+ # return
+ EventMesh.debug_log("socket:send data2 len:{}".format(len(data),self.IOT_sock))
except Exception as e:
- self.reconnect()
- self.socket_send_queue.put(data)#重新把数据加回队列
- #EventMesh.debug_log("socket_send_queue_thread1:ERROR:")
- #usys.print_exception(e)
- elif socketsta < 4:#正在连接,等待连接成功重新发送
- count = 0
- while True:
- if count > 15 :
- break
- utime.sleep(1)
- if(self.sock.getsocketsta() == 4):#
- try:
- self.sock.send(data)
- EventMesh.debug_log("TCP:send data3 len:{}".format(len(data)))
- except Exception as e:
- self.reconnect()
- self.socket_send_queue.put(data)#重新把数据加回队列
- #EventMesh.debug_log("socket_send_queue_thread2:ERROR:")
- #usys.print_exception(e)
+ EventMesh.debug_log("socket:send error")
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
break
- else :#连接错误
- EventMesh.debug_log("socket_send_queue_thread:ERROR:reconnect")
- self.reconnect()
- utime.sleep(1)
+
+
+ def iot_protocol_recv(self):
+ while True:
+ # 死循环接收数据
+ # with self.sock_lock: # 警告:不能加锁,不然会导致线程超长延时
+ socket_flag = self.IOT_sock.getsocketsta()
+ print("socket_flag = {}".format(socket_flag))
+ try:
+ data = self.IOT_sock.recv(256)
+ if isinstance(data, bytes) and len(data)>10:
+ playload_data(data)
+ socket_log.info("IOT_recv = {} ,len = {}".format(self.bytes_to_hex(data),len(data)))
+ if self.IOT_sock == None:
+ print("socket关闭退出send线程")
+ return
+ except Exception as e:
+ print("cli break")
+ print("异常是:{}".format(e))
+ # EventMesh.publish("connect_iot_websocket_cb")
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
+ break
+ self.iot_protoclo_recv_id =None
+ def decode_with_multiple_encodings(self, data):
+ #尝试多种常见编码格式解码,返回第一个成功的结果
+ # 常见编码格式列表(按优先级排序,根据实际场景调整)
+ encodings = ['utf-8', 'gbk', 'latin-1', 'utf-16', 'gb2312']
+
+ for encoding in encodings:
+ try:
+ # 尝试用当前编码解码,errors='strict'严格模式(确保无乱码)
+ return data.decode(encoding, errors='strict')
+ except UnicodeDecodeError:
+ continue # 解码失败,尝试下一种编码
+ return None # 所有编码都失败
+
+ # bytes转十六进制字符串
+ def bytes_to_hex(self, data):
+ #将bytes类型转换为十六进制字符串(如b'\x03\x01' -> '0301')
+ hex_chars = '0123456789abcdef'
+ hex_str = ''
+ for b in data:
+ # 处理每个字节的高4位和低4位
+ hex_str += hex_chars[(b >> 4) & 0x0F] # 高4位
+ hex_str += hex_chars[b & 0x0F] # 低4位
+ return hex_str
+
+ def iot_send_queue_close(self):
+ if self.socket_send_queue_id != None:
+ if self.iot_soc_send_queue.empty()!=True:
+ self.iot_soc_send_queue.clear()
+ try:
+ _thread.stop_thread(self.socket_send_queue_id)
+ except Exception as e:
+ print("iot_protoclo_recv_id !!!!!!!!")
+ print("iot_protoclo_recv_id 1111!!!!!!!!")
+ self.socket_send_queue_id = None
+
+ def iot_protoclo_recv_close_therad(self):
+ if self.iot_protoclo_recv_id != None:
+ try:
+ _thread.stop_thread(self.iot_protoclo_recv_id)
+ except Exception as e:
+ print("self.iot_protoclo_recv_id !!!!!!!!")
+ self.iot_protoclo_recv_id = None
+ if self.IOT_sock != None:
+ try:
+ print("关闭socket")
+ self.IOT_sock.close()
+ except Exception as e:
+ print("关闭socket失败")
+ self.IOT_sock = None
+
+
+
+ def iot_close_therad(self):
+ try:
+ self.iot_send_queue_close()
+ except Exception as e:
+ print("iot_send_queue_close error!!!!!!!!")
- def send(self, topic, msg):
+ try:
+ self.iot_protoclo_recv_close_therad()
+ except Exception as e:
+ print("iot_protoclo_recv_close_therad error!!!!!!!!")
+ self.start_voice_flag = 0
+ print("iot_close_therad")
+
+ def get_IOT_sock(self,event,msg):
+ return self.IOT_sock
+ def user_send(self,event,data):
+ # EventMesh.debug_log("TCP:send data:{}".format(msg))
# EventMesh.debug_log("TCP:send data:{}".format(msg))
- if EventMesh.publish("get_sim_Status") != 1: #没sim,则不发送
- EventMesh.publish(constants.EVENT.SET_CONNECT, 0)#标记断网
- EventMesh.debug_log("dataCall not connect")
+ sim_state = sim.getStatus()
+ if sim.getStatus() != 1:#网络不正常
+ print("无 sim卡")
return
else :
try:
- self.socket_send_queue.put(msg)
+ if self.start_voice_flag == 0: #如果关闭了就需要重新再
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
+ return
+ if data != None:
+ if len(data) != 0:
+ self.iot_soc_send_queue.put(data)
+ # EventMesh.debug_log("self.socket_send_queue.put:success:{}".format(len(data)))
except Exception as e:
EventMesh.debug_log("self.socket_send_queue.put:ERROR:")
usys.print_exception(e)
- # self.run_flag = False
-
- def recv(self):
- data = b''
- while True:
+
+ return
+ sim_state = sim.getStatus()
+ if sim_state != 1 or self.network_state == 0: #没sim,则不发送 ,没联网
+ return
+ else :
try:
- r = b''
- r = self.sock.recv(1024*5)
+ if self.IOT_sock != None:
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.iot_protocol_send_cb,"data":data})
+ else:
+ print("reconnect1 {}".format(data))
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
- if not r:
- self.run_flag = False
- self.reconnect()
-
- data = data + r
- EventMesh.debug_log("TCP recv: data:len:{}".format(len(data)))
- # EventMesh.debug_log("TCP recv: data:{}".format(data))
- if data[-1] != 0x5d and len(data)<20*1024: #']':
- continue
- self.connect_tmp = 1 #有数据,就认为是连接状态
- self.reconnect_time = 1000
- EventMesh.publish(constants.EVENT.SET_CONNECT, 1)
- data_str = data.decode('ascii')
- data_str = data_str.split(']')
- if len(data_str) < 3 :
- self.resolver.handler(data)
- else :
- for i in range(len(data_str)-1):
- self.resolver.handler(data_str[i])
-
- data = b''
- except Exception as e:
- #EventMesh.debug_log("TCP:ERROR:recv:")
- #usys.print_exception(e)
- self.run_flag = False
- self.reconnect()
+ except Exception as e:
+ print("senc data err reconnect{}".format(data))
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
- data = b''
- utime.sleep(2)
-
-
-
+ def iot_protocol_send_cb(self,data):
+ try:
+ if data != None:
+ print("socket connect success:{} self.IOT_sock:{}".format(data,self.IOT_sock))
+ if self.IOT_sock != None:
+ self.IOT_sock.send(data)
+ self.reconnect_count = 0
+ print("socket send success")
+ else:
+ print("reconnect2 {}".format(data))
+ # EventMesh.publish("connect_iot_socket_cb")
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
+ except Exception as e:
+ print("发送失败 重新连接")
+ self.reconnect_count+=1
+ # EventMesh.publish("connect_iot_socket_cb")
+ EventMesh.publish("publish_AI_btnInfo",{"func":self.connect_iot_socket})
+
+def bytes_ljust(data, length, fill_byte=b'\x00'):
+ """
+ 手动实现bytes的ljust功能:将字节流填充到指定长度,不足部分用fill_byte在右侧填充
+ :param data: 原始字节流(bytes)
+ :param length: 目标长度(int)
+ :param fill_byte: 填充字节(默认空字节b'\x00')
+ :return: 填充后的字节流(bytes)
+ """
+ if len(data) >= length:
+ # 若原始长度已超过目标长度,直接截断到指定长度
+ return data[:length]
+ else:
+ # 计算需要填充的长度,用fill_byte补齐
+ padding = fill_byte * (length - len(data))
+ return data + padding
+
class NetManager(Abstract):
THRESHOLD = 10
def get_network_state(self, topic, msg):
return self.network_state
-
class ProtoCol(Abstract):
TYPE = ""
HEADER = "#@{}@#;"
#EventMesh.debug_log(res)
#EventMesh.debug_log(MD5_head)
return MD5_head
+#查找设备
+class IOT_FindDeviceProtoCol(ProtoCol):
+ """find_device"""
+ TYPE = "find_device"
+ def send(self, event, msg):
+ # print("send locafind_devicetion{}".format(msg))
+ # 通过websocket发送到服务器端
+ date_tmp = utime.localtime()
+ time_tmp = utime.mktime(date_tmp)
+ find_device = {
+ "cmd":"dispatch_rest",
+ "ts":time_tmp,
+ "msg":"消息收到响应",
+ "data":{
+ "cmd":"find_device",
+ "rest":"success",
+ "msg":"收到查找设备指令"
+ }
+ }
+ send_data = b''
+ send_data = protocol_send_total_data(find_device)
+ print("send_data find_device{}".format(send_data))
+ EventMesh.publish("CHANNEL_IOT_SEND", send_data)
+
+ def recv(self, event, msg):
+ """
+
+ @param event:定位信息下发
+ @param msg: 接收到的下行数据
+ """
+ alarm_TTS_str="在这呢"
+ base_sentence = "{}".format(alarm_TTS_str)
+ repeat_sentence = (base_sentence + ",") * 3 # 重复5次并加逗号分隔
+ final_sentence = repeat_sentence.rstrip(",")
+
+ EventMesh.publish("play_tts",[final_sentence,1]) #播放tts闹钟文本内容
+ print("recv find_device{}".format(msg))
+ EventMesh.publish(WEB_CMD_ENUM.FIND_DEVCE_S_CMD)
+
+#上报设备VC状态
+class IOT_post_device_stateProtoCol(ProtoCol):
+ """post_device_state"""
+ TYPE = "post_device_state"
+
+ def send(self, event, msg):
+ print("send post_device_state{}".format(msg))
+ # 通过websocket发送到服务器端
+
+ send_data = b''
+ send_data = protocol_send_total_data(msg)
+ EventMesh.publish("CHANNEL_IOT_SEND",send_data)
+
+ def recv(self, event, msg):
+ """
+
+ @param event:mpost_device_state
+ @param msg: 接收到的下行数据
+ """
+ # locate_now = {
+ # "cmd":"locate_duration",
+ # "ts":1738283829,
+ # "msg":"下发定位周期",
+ # "data":300,0表示关
+ # }
+ print("send post_device_state{}".format(msg))
class LK_ProtoCol(ProtoCol):
"""链路保持"""
TYPE = "LK"
EventMesh.publish(constants.PROTOCOL.REMIND_SEND)
EventMesh.publish("clear_normal_alarm")
-
-
-
-
-
-
class HRSTART_ProtoCol(ProtoCol):
"""心率频率数据"""
TYPE = "hrtstart"
try:
if len(data) > 0:
#EventMesh.debug_log("handler:{}".format(len(data)))
- data_tmp = data.decode('ascii')
- data_tmp = data_tmp.split(']')[0] #去掉]
- ProtoCol_type = data_tmp.split('*')[3] #拿到协议标识
- ProtoCol_type = ProtoCol_type.split(',')[0]
- ProtoCol_type = "%s_RECV"%(ProtoCol_type)
- # EventMesh.debug_log("ProtoColResolver:ProtoCol_type:%s\r\ndata:%s"%(ProtoCol_type,data))
- EventMesh.publish(ProtoCol_type, data) #返回协议read
+ playload_data(data)
except Exception as e:
EventMesh.debug_log("handler:ERROR:")
usys.print_exception(e)
from machine import RTC
import usys
from Gsensor import SC7A20
+
def audio_cb(event):
if event == 0:
EventMesh.publish("set_audio_state", 1)
energe_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
self.meta = self.charge_full_screen
+
+
+ def post_processor_after_initialization(self):
self.count = 0
self.timer.start(1*1000,1,self.fun)
def fun(self,*argc):
EventMesh.publish("system_sleep_rest")#防止黑屏
self.count+=1
- if self.count > 2*60:
+ if self.count > 5:
self.count = 0
self.timer.stop()
- #EventMesh.publish("return_prev_screen")
+ EventMesh.publish("load_screen", {"screen": "main_menu"})
def done_click(self):
EventMesh.publish("return_prev_screen")
ai_img = lv.img(ui_screen)
ai_img.set_pos(0, 0)
ai_img.set_size(240, 320)
-ai_img.set_src("E:/static/listen.png")
+# ai_img.set_src("E:/static/listen.jpg")
+ai_img.set_src("E:/static/01.jpg")
ai_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
class UI_ai(Screen):
NAME = "UI_ai"
print("UI_ai:__init__")
self.meta = ui_screen
self.timer = osTimer()
-
+ self.image_sequences = {
+ # 为不同face_status定义图片序列,格式: [(图片路径, 显示时长), ...]
+ 0: [("E:/static/61.jpg", 0.5), #平常说
+ ("E:/static/62.jpg", 0.5)],
+ # 1: [("E:/static/dj1.jpg", 0.5), #大吉
+ # ("E:/static/dj2.jpg", 0.5)],
+ # 2: [("E:/static/zj1.jpg", 0.5),#中吉
+ # ("E:/static/zj2.jpg", 0.5)],
+ # 3: [("E:/static/j1.jpg", 0.5), #吉
+ # ("E:/static/j2.jpg", 0.5)],
+ # 4: [("E:/static/mj1.jpg", 0.5), #末吉
+ # ("E:/static/mj2.jpg", 0.5)],
+ 1: [("E:/static/61.jpg", 0.5), #大吉
+ ("E:/static/62.jpg", 0.5)],
+ 2: [("E:/static/61.jpg", 0.5),#中吉
+ ("E:/static/62.jpg", 0.5)],
+ 3: [("E:/static/61.jpg", 0.5), #吉
+ ("E:/static/62.jpg", 0.5)],
+ 4: [("E:/static/61.jpg", 0.5), #末吉
+ ("E:/static/62.jpg", 0.5)],
+ 5: [("E:/static/01.jpg", 0.5),
+ ("E:/static/02.jpg", 0.5)],#听
+ 6: [("E:/static/51.jpg", 0.5),
+ ("E:/static/52.jpg", 0.5)],#思考
+ }
+ self.current_sequence = None
+ self.sequence_thread = None
+ self.running = False
+ #硬件资源缓存标识,记录当前加载的图片路径
+ self.current_image_path = None
def initialization(self):
print("UI_ai:initialization")
#获取ai状态
ai_status = EventMesh.publish("screen_get_ai")
if ai_status:
- self.__ai_vc(None, ai_status)
- self.timer.start(500,1, self.timerout_update)
+ self.__ai_vc(None, ai_status,0)
+ self.timer.start(2000,1, self.timerout_update)
+ EventMesh.subscribe("UI_ai_close",self.UI_ai_close)
def timerout_update(self, *args):
EventMesh.publish("publish_message_event_ui",{"func":self.timerout_update_cb,"data":0})
EventMesh.publish("system_sleep_rest")#防止黑屏
#获取ai状态
ai_status = EventMesh.publish("screen_get_ai")
+ draw_status = EventMesh.publish("screen_get_draw")
+ # print ("draw_status = {}".format(draw_status))
# print("ai_status = {}".format(ai_status))
- self.__ai_vc(None, ai_status)
- def __ai_vc(self, event, msg):
+ self.__ai_vc(None, ai_status,draw_status)
+
+ def __ai_vc(self, event, msg,draw_status):
#msg = 1:listen,2:think,3:speak
+ # 记录上一次的face_status,避免重复启动
+ if not hasattr(self, "last_face_status"):
+ self.last_face_status = -1 # 初始化
+ target_status = None
if msg < 6:
- ai_img.set_src("E:/static/listen.png")#正在听
+ target_status = 5
elif msg == 6:
- ai_img.set_src("E:/static/think.png")#正在想
+ target_status = 6
elif msg == 8:
- ai_img.set_src("E:/static/speak.png")#正在说
- # elif msg == 14:
- # ai_img.set_src("E:/static/listen.png")#正在听
- pass
+ target_status = draw_status
+
+ # 仅当状态变化时,才启动新线程
+ if target_status is not None and target_status != self.last_face_status:
+ lv.img.cache_invalidate_src(None)
+ lv.img.cache_set_size(8)
+ EventMesh.publish("publish_message_event_ui", {"func": self.start_sequence, "data": target_status})
+ self.last_face_status = target_status # 更新状态
+ def UI_ai_close(self,event,msg):
+ if self.running:
+ self.stop_sequence()
+ self.timer.stop()
+ lv.img.cache_invalidate_src(None)
+ lv.img.cache_set_size(8)
+
+ def start_sequence(self, face_status):
+ #停止当前序列(确保旧线程退出)
+ if self.running:
+ self.stop_sequence()
+ #强制等待旧线程彻底退出(延长等待时间+主动清理)
+ start_wait = utime.time()
+ while self.sequence_thread is not None:
+ utime.sleep(0.05) # 更短间隔检测
+ if utime.time() - start_wait > 2: # 延长等待至2秒
+ print("警告:旧线程超时未退出,强制清理")
+ self.sequence_thread = None # 强制重置标识
+ break
+
+ # 启动新线程前清理硬件资源
+ if self.current_image_path:
+ self.current_image_path = None # 重置路径记录
+
+ #启动新线程
+ if face_status in self.image_sequences:
+ self.current_sequence = self.image_sequences[face_status]
+ self.running = True
+ self.sequence_thread = _thread.start_new_thread(self._play_sequence, ())
+ print("启动新线程")
+
+ def stop_sequence(self):
+ #停止当前图片序列轮播
+ self.running = False # 仅设置标志位,让线程自然退出
+ # 等待线程退出(最多等待1秒,避免无限阻塞)
+ start_wait = utime.time()
+ while self.sequence_thread is not None and utime.time() - start_wait < 2:
+ utime.sleep(0.1) # 短休眠等待
+ def _play_sequence(self):
+ try:
+ while self.running:
+ current = list(self.current_sequence)
+ if not current:
+ utime.sleep(0.1)
+ continue
+ for image_path, duration in current:
+ if not self.running:
+ break
+ # 硬件操作添加超时和详细日志
+ try:
+ # 记录开始时间,防止set_src无限阻塞
+ set_start = utime.time()
+ ai_img.set_src(image_path)
+ # 检查set_src是否耗时过长
+ # 记录当前图片路径,用于后续清理
+ self.current_image_path = image_path
+ if utime.time() - set_start > 1:
+ print("警告:set_src()耗时过长")
+ except OSError as e: # 捕获硬件相关错误
+ print("硬件错误:设置图片失败")
+ # 发生硬件错误后,暂停轮播避免持续冲突
+ self.running = False
+ break
+ except Exception as e:
+ print("未知错误:设置图片失败")
+ continue
+
+ # 分段休眠逻辑保持,但增加超时保护
+ start_time = utime.time()
+ sleep_ok = True
+ while utime.time() - start_time < duration:
+ if not self.running:
+ sleep_ok = False
+ break
+ utime.sleep(0.05)
+ if not sleep_ok:
+ break
+ utime.sleep(0.1)
+ except Exception as e:
+ print("轮播线程异常(致命)")
+ finally:
+ # 加锁确保线程安全
+ self.running = False
+ self.sequence_thread = None
+ self.current_image_path = None
+ print("轮播线程已退出并释放资源")
+
def post_processor_before_initialization(self):
pass
def post_processor_after_initialization(self):
return self.meta
def Close(self):
self.timer.stop()
+ EventMesh.publish("return_prev_screen")
message_popup_screen = None
message_popup_title = None
#信息弹窗
Lowpower_screen.add_style(style_screen, lv.PART.MAIN|lv.STATE.DEFAULT)
#进入图片
Lowpower_screen_img = lv.img(Lowpower_screen)
- Lowpower_screen_img.set_pos(int(40),int(45))
- Lowpower_screen_img.set_size(160,230)
+ Lowpower_screen_img.set_pos(int(0),int(0))
+ Lowpower_screen_img.set_size(240,320)
Lowpower_screen_img.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
Lowpower_screen_img.add_flag(lv.obj.FLAG.CLICKABLE)
Lowpower_screen_img.set_src("E:/static/low_power.png")
# charge_in_screen_label.set_long_mode(lv.label.LONG.WRAP)
# charge_in_screen_label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
- charge_out_img = lv.img(self.charge_in_screen)
- charge_out_img.set_size(240, 320)
- charge_out_img.set_src("E:/static/charge_in.png")
- charge_out_img.add_flag(lv.obj.FLAG.CLICKABLE)
- charge_out_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
- charge_out_img.set_pos(0, 0)
+ charge_in_img = lv.img(self.charge_in_screen)
+ charge_in_img.set_size(240, 320)
+ charge_in_img.set_src("E:/static/charge_in.png")
+ charge_in_img.add_flag(lv.obj.FLAG.CLICKABLE)
+ charge_in_img.add_style(style_img, lv.PART.MAIN | lv.STATE.DEFAULT)
+ charge_in_img.set_pos(0, 0)
self.meta = self.charge_in_screen
+
def post_processor_after_initialization(self):
self.count+=1
if self.count >= 5:
self.count = 0
- EventMesh.publish("return_prev_screen")
+ self.timer.stop()
+ EventMesh.publish("load_screen", {"screen": "main_menu"})
def done_left_to_right(self):
self.rotate_flag = 0 #0为原来的,1为垂直翻转后的
if self.level == None:
- self.level = 6
+ self.level = 10
self.PWM_backlight = PWM(PWM.PWM1, PWM.ABOVE_MS, self.level, 10)
self.PWM_backlight.open()
self.gsensor = SC7A20()
def set_rotation(self,angle):#软件设置屏幕方向
global disp_drv
PWM_backlight.close()
+ if disp_drv.rotated == angle:
+ return
disp_drv.rotated = angle
# 重新注册驱动
disp_drv.register()
+ lv.img.cache_invalidate_src(None)
+ lv.img.cache_set_size(8)
# 刷新屏幕
lv.scr_load(lv.scr_act())
- utime.sleep_ms(200)
+ utime.sleep_ms(750)
PWM_backlight.open()
def gsensor_cb(self, para):
utime.sleep_ms(60)
self.level = EventMesh.publish("get_brightness_level")
if self.level == None:
- self.level = 6
+ self.level = 10
elif self.level > 10:
self.level = 10
elif self.level <= 0:
self.level = 1
+ EventMesh.publish("load_screen", {"screen": "main_menu"})
+ utime.sleep_ms(150)
self.PWM_backlight = PWM(PWM.PWM1, PWM.ABOVE_MS, self.level, 10)
self.PWM_backlight.open()
+
self.sleep_lock = 0
self.PWM_backlight.open()
#lcd_ctrl.write(0)
#
+ #检测闹钟是否还存在,若存在不关闭定时器,若没有闹钟则关闭定时器
+
+ get_have_alarm = EventMesh.publish("get_have_alarm")
+ if get_have_alarm == 0:#不存在闹钟
+ alarm_timer_sta = EventMesh.publish("alarm_get_statu")#看定时器是否开启
+ if alarm_timer_sta == 1 :#当定时器开启时
+ EventMesh.publish("AI_alarm_close")#关闭轮询
+ alarm_timer_sta = 0
lv.autoSleep(1)
pm.autosleep(1)
pm.sclkEx_set(1, 1, 5)
EventMesh.publish("set_lcd_state",self.sleep_flag)
self.sleep_lock = 0
self.screen.lcd_off()
+ self.screen.Close()
self.system_sleep_timer.stop()
EventMesh.publish("Hsensor_set_sleep") #让系统更快休眠
if self.screen_old != None :
self.screen_old.Close() #先关闭上一次界面
self.lv.img.cache_invalidate_src(None) #清img cache
- self.lv.img.cache_set_size(16) #开img cache
+ self.lv.img.cache_set_size(8) #开img cache
if self.screen.meta_type != "popup": #只要当前界面不是弹窗界面都要保存当前界面
if self.screen_old.meta_type != "popup":#上个界面也不为弹窗界面
self.screen_prev = self.screen_old #第二种方式
print("load_screen:post_processor_before_initialization")
self.screen.post_processor_before_initialization()
self.screen_old = self.screen
+ utime.sleep_ms(100)
print("load_screen:initialization")
self.screen.initialization()
print("load_screen.load()1")
+
self.screen.load()
#print("load_screen.load()2")
self.lv.scr_load(self.screen.get_meta())
- #print("load_screen.load()3")
-
- self.screen.post_processor_after_initialization()
- #print("load_screen.load()4")
if self.screen_prev == None:
if self.screen.meta_type != "popup":
self.screen_prev = self.screen
+ #print("load_screen.load()3")
self.__lcd_on()
+ utime.sleep_ms(100)
+ self.screen.post_processor_after_initialization()
+ #print("load_screen.load()4")
+
+ # self.__lcd_on()
#print("load_screen.load()5")
mem = gc.mem_free()
#print('2剩余内存RAM:{} KB'.format(mem / 1024))
watchface1_time1_text = lv.label(Watchface1)
-watchface1_time1_text.set_pos(30, 139)
+watchface1_time1_text.set_pos(30, 110)
watchface1_time1_text.set_size(240, 71)
watchface1_time1_text.set_align(lv.TEXT_ALIGN.LEFT)
watchface1_time1_text.set_text("{}:{}".format("%02d"%(hour),"%02d"%(min)))
#日期
watchface1_date_span = lv.label(Watchface1)
-watchface1_date_span.set_pos(8, 122)
-watchface1_date_span.set_size(140, 30)
+watchface1_date_span.set_pos(85, 191)
+watchface1_date_span.set_size(140, 50)
watchface1_date_span.set_align(lv.TEXT_ALIGN.LEFT)
watchface1_date_span.set_text("")
watchface1_date_span.add_style(style_font_youyuan_28, lv.PART.MAIN|lv.STATE.DEFAULT)
#星期
watchface1_week_span = lv.label(Watchface1)
-watchface1_week_span.set_pos(8, 160)
+watchface1_week_span.set_pos(85, 230)
watchface1_week_span.set_size(100, 30)
watchface1_week_span.set_align(lv.TEXT_ALIGN.LEFT)
watchface1_week_span.set_text("")
self.__stepValue(None, step)
def timerout_update(self):
+ # print("主界面定时器在更新")
signal = EventMesh.publish("screen_get_sig")
if signal:
self.__signal(None, signal)
def __time(self, event, msg):
#时间
watchface1_time1_text.set_text("{}:{}".format("%02d"%(msg[0][0]),"%02d"%(msg[0][1])))
-
- # watchface1_date_span.set_text(msg[2])#日期
- # watchface1_week_span.set_text(msg[3]) #星期
+ watchface1_date_span.set_text(msg[2])#日期
+ watchface1_week_span.set_text(msg[3]) #星期
def __signal(self, event, msg):
#print("__signal_cb:",str(msg))
Version="V1.0"
-Build_Time="2025-06-27 17:53:06"
+Build_Time="2025-09-12 17:53:45"