本帖最后由 zoey不种土豆 于 2025-1-24 20:01 编辑  
 
 
WatchHIKER是一个基于行空板M10的“智能手表”,其外壳由3D打印制作,通过Mind+进行低代码可视化编程。除了可定制的UI界面,作者为该手表设计超过10个功能,包括计步、心率监测、路况查询、天气情况和空气质量查询、紧急联系人、一键录音、噪音检测等,甚至还能查看实时货币行情。 
 
所需材料  
硬件 
 
软件 
 
其他 
 
 外壳设计和硬件组装 
使用Fusion设计WatchHIKER的外壳,作者在背壳上预留了方便腕带穿过的空隙。打印完成后,将行空板M10以屏幕朝外的方向放入外壳内,接下来,连接电池到充电器模块,将组装完成的电池组安装在外壳里。完成以上步骤后,封闭外壳。最后给手表加上表带,作者选择的是“魔术贴”腕带。 
 加载Python脚本 
在行空板上打开文件共享并复制完整的Git文件夹。 
 
这里有几段代码用来实现以下功能: 
 
1.GUI(图形用户界面)自定义 
使用 tkinter 库来创建GUI(图形用户界面),并设计了三种不同风格的时钟界面。 
 
 
 
 
2.心率监测 
 
要实现这个功能,我们还需要添加以下两个硬件:Beetle ESP32-C3和心率传感器。  首先将Beetle ESP32 C3编程,让它通过I2C通信从心率传感器读取数据,并将其写入串行端口。这样,行空板就可以读取并绘制血氧饱和度和心率数据了。 
 
输出心率与血氧饱和度的代码: 
			
			
			- <blockquote><span style="white-space: normal;"><span style="white-space:pre">        </span>#include <Wire.h></span>
 
  复制代码
  
以下是串行终端响应: 
现在,用程序来解码和填充数据:  
 
接下来,在Mind+中运行该脚本 
 
3.计步功能 
行空板M10的板载三轴陀螺仪和加速度传感器,因此可以实现WatchHIKER的计步功能。 
- <blockquote><span style="white-space: normal;"><span style="white-space:pre">        </span>import tkinter as tk</span>
 
  复制代码
  
4.天气情况和空气质量查询 
 
此脚本允许添加若干城市,并从开放的天气API中读取并显示当地的天气、温度、湿度和风力级别等。 
 
 
该脚本可以通过HTTP请求从远程API获取数据,并在界面上显示所在城市的PM2.5、PM10和其他空气污染物的浓度。使用者还可以通过点击“Refresh Data(刷新数据)”按钮来更新信息。 
 
5.紧急联系人 
 
 
一键SOS呼叫,快速将所在位置发送给紧急联系人。 
 
6.路况查询 
 
路况检测器提供实时路况更新,帮助使用者选择最快的路线。 
 
7.录音功能 
- #  -*- coding: UTF-8 -*-
 - 
 - # MindPlus
 - # Python
 - from unihiker import Audio
 - import tkinter as tk
 - from tkinter import ttk
 - import time
 - import threading
 - from datetime import datetime
 - import os
 - 
 - class AudioRecorder:
 -     def __init__(self):
 -         self.root = tk.Tk()
 -         self.root.title("Audio Recorder")
 -         self.root.geometry("240x320")
 -         self.root.configure(bg="#1e1e1e")
 -         
 -         self.audio = Audio()
 -         self.recording = False
 -         self.elapsed_time = 0
 -         self.recordings_dir = "recordings"
 -         if not os.path.exists(self.recordings_dir):
 -             os.makedirs(self.recordings_dir)
 -         self.setup_ui()
 -         
 -     def setup_ui(self):
 -         # Main container frame
 -         main_frame = tk.Frame(self.root, bg="#1e1e1e")
 -         main_frame.pack(expand=True, fill="both")
 -         
 -         # Toggle button for start/stop
 -         self.toggle_btn = tk.Button(
 -             main_frame,
 -             text="START",
 -             command=self.toggle_recording,
 -             bg="#00ff00",
 -             fg="#000000",
 -             width=20,
 -             height=2,
 -             font=("Arial", 16, "bold")
 -         )
 -         self.toggle_btn.pack(pady=10)
 -         
 -         # Status text
 -         self.status_label = tk.Label(
 -             main_frame,
 -             text="Ready to Record",
 -             font=("Arial", 16),
 -             bg="#1e1e1e",
 -             fg="#00ff00"
 -         )
 -         self.status_label.pack(pady=10)
 -         
 -         # Recording indicator
 -         self.canvas = tk.Canvas(
 -             main_frame,
 -             width=100,
 -             height=100,
 -             bg="#1e1e1e",
 -             highlightthickness=0
 -         )
 -         self.canvas.pack(pady=10)
 -         
 -         self.indicator = self.canvas.create_oval(
 -             25, 25, 75, 75,
 -             fill="#1e1e1e",
 -             outline="#ff0000",
 -             width=2
 -         )
 -         
 -         # Timer display
 -         self.timer_label = tk.Label(
 -             main_frame,
 -             text="00:00",
 -             font=("Arial", 24),
 -             bg="#1e1e1e",
 -             fg="#ffffff"
 -         )
 -         self.timer_label.pack(pady=10)
 -     
 -     def update_timer(self):
 -         while self.recording:
 -             self.elapsed_time += 1
 -             minutes = self.elapsed_time // 60
 -             seconds = self.elapsed_time % 60
 -             self.timer_label.config(text=f"{minutes:02d}:{seconds:02d}")
 -             time.sleep(1)
 -     
 -     def animate_indicator(self):
 -         pulse_state = True
 -         while self.recording:
 -             self.canvas.itemconfig(
 -                 self.indicator,
 -                 fill="#ff0000" if pulse_state else "#1e1e1e"
 -             )
 -             pulse_state = not pulse_state
 -             time.sleep(0.5)
 -     
 -     def toggle_recording(self):
 -         if not self.recording:
 -             # Start Recording
 -             self.recording = True
 -             self.elapsed_time = 0
 -             
 -             # Generate unique filename
 -             timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
 -             self.current_file = os.path.join(self.recordings_dir, f"recording_{timestamp}.wav")
 -             
 -             self.status_label.config(text="Recording...")
 -             self.toggle_btn.config(
 -                 text="STOP",
 -                 bg="#ff0000",
 -                 fg="#ffffff"
 -             )
 -             
 -             # Start recording in separate thread
 -             threading.Thread(target=self.audio.start_record, args=(self.current_file,), daemon=True).start()
 -             
 -             # Start timer and animation
 -             threading.Thread(target=self.update_timer, daemon=True).start()
 -             threading.Thread(target=self.animate_indicator, daemon=True).start()
 -         else:
 -             # Stop Recording
 -             self.recording = False
 -             self.audio.stop_record()
 -             self.status_label.config(text=f"Saved: {os.path.basename(self.current_file)}")
 -             self.toggle_btn.config(
 -                 text="START",
 -                 bg="#00ff00",
 -                 fg="#000000"
 -             )
 -             self.canvas.itemconfig(self.indicator, fill="#1e1e1e")
 -     
 -     def run(self):
 -         self.root.mainloop()
 - 
 - if __name__ == "__main__":
 -     app = AudioRecorder()
 -     app.run()
 
  复制代码
  
使用者可以通过点击按钮开始或停止录音,录音文件会保存到指定的目录中。 
 
8.噪音监测 
- #  -*- coding: UTF-8 -*-
 - 
 - # MindPlus
 - # Python
 - from pinpong.extension.unihiker import *
 - from pinpong.board import Board,Pin
 - from unihiker import Audio
 - import tkinter as tk
 - from tkinter import ttk
 - import time
 - import threading
 - import math
 - 
 - class NoiseMonitor:
 -     def __init__(self):
 -         self.root = tk.Tk()
 -         self.root.title("Noise Monitor")
 -         self.root.geometry("240x320")
 -         self.root.configure(bg="#1e1e1e")
 -         
 -         self.audio = Audio()
 -         self.setup_ui()
 -         self.start_monitoring()
 -     
 -     def setup_ui(self):
 -         # Title
 -         self.title_label = tk.Label(
 -             self.root,
 -             text="NOISE MONITOR",
 -             font=("Arial", 16, "bold"),
 -             bg="#1e1e1e",
 -             fg="#00ff00"
 -         )
 -         self.title_label.pack(pady=10)
 -         
 -         # Canvas for visualization
 -         self.canvas = tk.Canvas(
 -             self.root,
 -             width=200,
 -             height=150,
 -             bg="#1e1e1e",
 -             highlightthickness=0
 -         )
 -         self.canvas.pack(pady=10)
 -         
 -         # Create bars with peak indicators
 -         self.bars = []
 -         self.peaks = []
 -         self.peak_speeds = []
 -         num_bars = 16
 -         
 -         for i in range(num_bars):
 -             # Create main bar
 -             bar = self.canvas.create_rectangle(
 -                 i*12 + 5, 150,
 -                 i*12 + 13, 150,
 -                 fill="#00ff00"
 -             )
 -             self.bars.append(bar)
 -             
 -             # Create peak indicator
 -             peak = self.canvas.create_rectangle(
 -                 i*12 + 5, 150,
 -                 i*12 + 13, 148,
 -                 fill="#ffffff"
 -             )
 -             self.peaks.append(peak)
 -             self.peak_speeds.append(0)
 -         
 -         # Numerical display
 -         self.level_label = tk.Label(
 -             self.root,
 -             text="0",
 -             font=("Arial", 36, "bold"),
 -             bg="#1e1e1e",
 -             fg="#00ff00"
 -         )
 -         self.level_label.pack(pady=10)
 -         
 -         # Status bar
 -         self.status_bar = tk.Label(
 -             self.root,
 -             text="Monitoring...",
 -             bg="#1e1e1e",
 -             fg="#ffffff",
 -             bd=1,
 -             relief=tk.SUNKEN
 -         )
 -         self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
 -     
 -     def update_visualization(self, level):
 -         max_height = 150
 -         peak_fall_speed = 0.5
 -         
 -         for i, (bar, peak) in enumerate(zip(self.bars, self.peaks)):
 -             # Calculate bar height with some randomness
 -             variation = math.sin(time.time() * 10 + i) * 5
 -             adjusted_level = max(0, min(100, level + variation))
 -             
 -             # Calculate height and color
 -             height = max_height - (adjusted_level * 1.2)
 -             
 -             # Rainbow color effect
 -             hue = (i / len(self.bars)) * 360
 -             rgb = self.hsv_to_rgb(hue, 1, 1 if adjusted_level > 0 else 0.2)
 -             color = f'#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}'
 -             
 -             # Update bar
 -             self.canvas.coords(bar, i*12 + 5, height, i*12 + 13, max_height)
 -             self.canvas.itemconfig(bar, fill=color)
 -             
 -             # Update peak
 -             peak_y = float(self.canvas.coords(peak)[1])
 -             if height < peak_y:  # New peak
 -                 self.canvas.coords(peak, i*12 + 5, height, i*12 + 13, height + 2)
 -                 self.peak_speeds[i] = 0
 -             else:  # Peak falling
 -                 self.peak_speeds[i] += peak_fall_speed
 -                 new_y = min(max_height, peak_y + self.peak_speeds[i])
 -                 self.canvas.coords(peak, i*12 + 5, new_y, i*12 + 13, new_y + 2)
 -         
 -         # Update level display
 -         self.level_label.config(text=str(int(level)))
 -         
 -         # Update status with smooth color transition
 -         if level > 80:
 -             status = "Very Loud!"
 -             color = "#ff0000"
 -         elif level > 60:
 -             status = "Loud"
 -             color = "#ffff00"
 -         else:
 -             status = "Normal"
 -             color = "#00ff00"
 -         
 -         self.status_bar.config(text=status, fg=color)
 -     
 -     def hsv_to_rgb(self, h, s, v):
 -         h = float(h)
 -         s = float(s)
 -         v = float(v)
 -         h60 = h / 60.0
 -         h60f = math.floor(h60)
 -         hi = int(h60f) % 6
 -         f = h60 - h60f
 -         p = v * (1 - s)
 -         q = v * (1 - f * s)
 -         t = v * (1 - (1 - f) * s)
 -         r, g, b = 0, 0, 0
 -         if hi == 0: r, g, b = v, t, p
 -         elif hi == 1: r, g, b = q, v, p
 -         elif hi == 2: r, g, b = p, v, t
 -         elif hi == 3: r, g, b = p, q, v
 -         elif hi == 4: r, g, b = t, p, v
 -         elif hi == 5: r, g, b = v, p, q
 -         return (
 -             int(r * 255),
 -             int(g * 255),
 -             int(b * 255)
 -         )
 -     
 -     def monitor_audio(self):
 -         while True:
 -             try:
 -                 level = self.audio.sound_level()
 -                 self.root.after(0, self.update_visualization, level)
 -                 time.sleep(0.1)
 -             except Exception as e:
 -                 print(f"Error: {e}")
 -                 time.sleep(1)
 -     
 -     def start_monitoring(self):
 -         threading.Thread(target=self.monitor_audio, daemon=True).start()
 -     
 -     def run(self):
 -         self.root.mainloop()
 - 
 - if __name__ == "__main__":
 -     app = NoiseMonitor()
 -     app.run()
 
  复制代码
  
监测周围噪音水平,并在分贝超过正常范围时进行提醒。 
 
9.查看实时货币行情 
 
 
数据的实时更新,对于货币交易的操盘者来说十分重要,而这款手表也能为你做到信息的实时更新。 
 
其它功能 
除了以上功能,你还可以开动你的想象力,为WatchHIKER增加更多功能,比如,连接Beetle ESP32 C6,用于监控并在手表上探测到的家里是否有物体移动情况...... 
 
项目文件  watchhiker.rar 
 
原文链接: https://community.dfrobot.com/makelog-315081.html 
项目作者:pradeeplogu0 
发表时间:2025.01.12 
 
 |