实现单例任务,可推送新任务功能,垃圾回收功能。

This commit is contained in:
2025-04-27 00:46:21 +08:00
parent 8aa87900bf
commit 484c20a5ef
4 changed files with 92 additions and 46 deletions

View File

@@ -8,6 +8,8 @@ from machine import Pin, I2S
import ubinascii import ubinascii
import urandom import urandom
import shared_vars
# I2S 引脚配置 # I2S 引脚配置
BCLK_PIN = 13 BCLK_PIN = 13
WS_PIN = 12 WS_PIN = 12
@@ -38,7 +40,6 @@ def init_i2s():
ibuf=BUFFER_SIZE) # 输入缓冲区大小 ibuf=BUFFER_SIZE) # 输入缓冲区大小
return i2s return i2s
class InterphoneHandler: class InterphoneHandler:
def play_wav_file(self, data): def play_wav_file(self, data):
@@ -67,41 +68,41 @@ class InterphoneHandler:
if 'audio_out' in locals(): if 'audio_out' in locals():
audio_out.deinit() audio_out.deinit()
def play_audio_stream(self, i2s, url): def stream_and_play(self, data):
current_task_id = shared_vars.handle_task_id
url = "https://iot.julecn.com/interphone/get_voice?name=" + data['name'] # 替换为音频文件的URL
print(url)
try: try:
# 添加请求头信息 print("添加请求头信息")
headers = { headers = {
'User-Agent': 'MicroPython v1.0.0' 'User-Agent': 'MicroPython v1.0.0'
} }
# 发送 HTTP 请求,获取流式响应 print("发送 HTTP 请求,获取流式响应")
response = urequests.get(url, headers=headers, stream=True) response = urequests.get(url, headers=headers, stream=True)
# 检查响应状态码 print("检查响应状态码")
if response.status_code != 200: if response.status_code != 200:
print(f"请求失败,状态码: {response.status_code}") print(f"请求失败,状态码: {response.status_code}")
response.close() response.close()
return return
print("解析 WAV 头部")
# 解析 WAV 头部
header = response.raw.read(44) header = response.raw.read(44)
if len(header) != 44 or header[0:4] != b'RIFF' or header[8:12] != b'WAVE' or header[12:16] != b'fmt ': if len(header) != 44 or header[0:4] != b'RIFF' or header[8:12] != b'WAVE' or header[12:16] != b'fmt ':
print(header) print(header)
raise ValueError("Not a valid WAV file") raise ValueError("Not a valid WAV file")
# 提取采样率、位深、声道数 print("提取采样率、位深、声道数")
global SAMPLE_RATE, BITS_PER_SAMPLE, CHANNELS global SAMPLE_RATE, BITS_PER_SAMPLE, CHANNELS
SAMPLE_RATE = int.from_bytes(header[24:28], 'little') SAMPLE_RATE = int.from_bytes(header[24:28], 'little')
BITS_PER_SAMPLE = int.from_bytes(header[34:36], 'little') BITS_PER_SAMPLE = int.from_bytes(header[34:36], 'little')
CHANNELS = int.from_bytes(header[22:24], 'little') CHANNELS = int.from_bytes(header[22:24], 'little')
# 重新初始化 I2S 输出 print("初始化 I2S 输出")
audio_out = init_i2s() audio_out = init_i2s()
print("开始流式播放")
# 开始流式播放 chunk_size = 512
chunk_size = 1024 while shared_vars.handle_task_id == current_task_id:
while True:
chunk = response.raw.read(chunk_size) chunk = response.raw.read(chunk_size)
if not chunk: if not chunk:
break break
@@ -114,26 +115,8 @@ class InterphoneHandler:
audio_out.deinit() audio_out.deinit()
if 'response' in locals(): if 'response' in locals():
response.close() response.close()
print('音频播放完成')
def stream_and_play(self, data): def stop_playing(self, data):
i2s = init_i2s() print("停止播放音频")
url = "http://iot.julecn.com/interphone/get_voice?name=" + data['name'] # 替换为音频文件的URL pass
print(url)
self.play_audio_stream(i2s, url)
def generate_random_hex():
# 初始化一个空的字节数组,用于存储随机字节
random_bytes = bytearray()
# 循环 4 次,每次生成 32 位4 字节)的随机数
for _ in range(4):
# 生成 32 位随机数
rand_32_bits = urandom.getrandbits(32)
# 将 32 位随机数转换为 4 字节,并添加到字节数组中
random_bytes.extend(rand_32_bits.to_bytes(4, 'big'))
# 将随机字节转换为十六进制字符串
hex_string = ubinascii.hexlify(random_bytes).decode()
return hex_string

41
SingletonThreadPool.py Normal file
View File

@@ -0,0 +1,41 @@
import _thread
import time
import gc
class SingletonThreadPool:
_instance = None
def __new__(cls):
if not cls._instance:
pool_size = 2
cls._instance = super().__new__(cls)
cls._instance.pool_size = pool_size
cls._instance.task_queue = []
cls._instance.pool_lock = _thread.allocate_lock()
# 创建线程池
for _ in range(pool_size):
_thread.start_new_thread(cls._instance.worker, ())
return cls._instance
def worker(self):
while True:
self.pool_lock.acquire()
if self.task_queue:
task, args = self.task_queue.pop(0)
self.pool_lock.release()
try:
task(*args)
gc.collect()
except Exception as e:
print(f"Task execution error: {e}")
else:
self.pool_lock.release()
time.sleep(0.1)
def add_task(self, task, *args):
self.pool_lock.acquire()
self.task_queue.append((task, args))
self.pool_lock.release()

35
boot.py
View File

@@ -7,10 +7,17 @@ import urandom
import hashlib import hashlib
import _thread import _thread
import ujson import ujson
import gc
import shared_vars
from SingletonThreadPool import SingletonThreadPool
from InterphoneHandler import InterphoneHandler from InterphoneHandler import InterphoneHandler
gc.enable()
# Wi-Fi配置 # Wi-Fi配置
WIFI_SSID = "JULM" WIFI_SSID = "JULM"
WIFI_PASSWORD = "11223344" WIFI_PASSWORD = "11223344"
@@ -127,16 +134,19 @@ def handle_action(action, data):
method = getattr(handler, method_part, None) method = getattr(handler, method_part, None)
if method and callable(method): if method and callable(method):
print(f"执行 {action} 方法") print(f"执行 {action} 方法")
method(data) shared_vars.handle_task_id = generate_random_hex()
#method(data)
thread_pool = SingletonThreadPool()
thread_pool.add_task(method,data)
else: else:
print(f"处理器 {class_part} 没有方法: {method_part}") print(f"处理器 {class_part} 没有方法: {method_part}")
except Exception as e: except Exception as e:
print(f"执行 {action} 失败: {str(e)}") print(f"执行 {action} 失败: {str(e)}")
def handle_new_data(data): def handle_new_data(data):
print(f"接收到新数据: {data}") print(f"接收到新数据: {data}")
# 修改后的处理逻辑
try: try:
# 解析JSON数据 # 解析JSON数据
message = ujson.loads(data) message = ujson.loads(data)
@@ -151,7 +161,6 @@ def handle_new_data(data):
except Exception as e: except Exception as e:
print(f"数据处理异常: {str(e)}") print(f"数据处理异常: {str(e)}")
def receive_message(sock): def receive_message(sock):
header = b"" header = b""
while len(header) < 2: # 确保接收到至少2字节头部 while len(header) < 2: # 确保接收到至少2字节头部
@@ -233,7 +242,6 @@ def send_text(sock, message):
print(f"发送失败:{str(e)}") print(f"发送失败:{str(e)}")
raise # 抛出异常供上层处理 raise # 抛出异常供上层处理
# 启动接收数据的线程 # 启动接收数据的线程
_thread.start_new_thread(websocket_receive_thread, ()) _thread.start_new_thread(websocket_receive_thread, ())
@@ -261,8 +269,6 @@ def ws_client():
time.sleep(5) time.sleep(5)
reset() reset()
def force_cleanup(): def force_cleanup():
"""强制清理残留资源""" """强制清理残留资源"""
global WS_SOCK global WS_SOCK
@@ -288,4 +294,19 @@ def check_connection_alive():
return False return False
raise raise
def generate_random_hex():
# 初始化一个空的字节数组,用于存储随机字节
random_bytes = bytearray()
# 循环 4 次,每次生成 32 位4 字节)的随机数
for _ in range(4):
# 生成 32 位随机数
rand_32_bits = urandom.getrandbits(32)
# 将 32 位随机数转换为 4 字节,并添加到字节数组中
random_bytes.extend(rand_32_bits.to_bytes(4, 'big'))
# 将随机字节转换为十六进制字符串
hex_string = ubinascii.hexlify(random_bytes).decode()
return hex_string
ws_client() ws_client()

1
shared_vars.py Normal file
View File

@@ -0,0 +1 @@
handle_task_id = None