moki 6 godzin temu
rodzic
commit
a4e1fda2bc

+ 7 - 3
src/composables/useBleDevice.ts

@@ -1,4 +1,4 @@
-import { ref, readonly } from 'vue'
+import {readonly, ref} from 'vue'
 
 const SERVICE_UUID = 'b8b7e001-7a6b-4f4f-9a8b-11c0ffee0001'
 const MODE_UUID = 'b8b7e002-7a6b-4f4f-9a8b-11c0ffee0001'
@@ -18,7 +18,8 @@ export interface BleDeviceConfig {
   comm_mode: number
   pin_red: number
   pin_green: number
-  pin_yellow: number
+    pin_blue?: number
+    pin_yellow?: number
 }
 
 interface BluetoothChar {
@@ -83,7 +84,10 @@ export function useBleDevice() {
 
       if (!device) {
         device = await bluetooth.requestDevice({
-          filters: [{ name: 'AI-Light' }],
+            filters: [
+                {name: 'AI-Beacon-Light'},
+                {name: 'AI-Traffic-Light'}
+            ],
           optionalServices: [SERVICE_UUID],
         })
         device.addEventListener('gattserverdisconnected', onDisconnected)

+ 2 - 1
src/composables/useDeviceConfig.ts

@@ -18,7 +18,8 @@ export interface DeviceConfigData {
     mqtt_topic_config: string
     pin_red: number
     pin_green: number
-    pin_yellow: number
+    pin_blue?: number
+    pin_yellow?: number
     enabled: boolean
 }
 

+ 8 - 8
src/views/BleConfig.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
-import { ref, reactive, onMounted, onUnmounted } from 'vue'
-import { message, Modal } from 'ant-design-vue'
-import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue'
-import { getBleList, createBle, updateBle, deleteBle } from '@/api/ble'
-import type { BleConfig, BleConfigForm } from '@/types'
+import {onMounted, onUnmounted, reactive, ref} from 'vue'
+import {message, Modal} from 'ant-design-vue'
+import {DeleteOutlined, EditOutlined, PlusOutlined} from '@ant-design/icons-vue'
+import {createBle, deleteBle, getBleList, updateBle} from '@/api/ble'
+import type {BleConfig, BleConfigForm} from '@/types'
 
 const loading = ref(false)
 const list = ref<BleConfig[]>([])
@@ -16,7 +16,7 @@ const DEFAULT_MODE_CHAR_UUID = 'b8b7e002-7a6b-4f4f-9a8b-11c0ffee0001'
 const DEFAULT_CONFIG_CHAR_UUID = 'b8b7e003-7a6b-4f4f-9a8b-11c0ffee0001'
 
 const form = reactive<BleConfigForm>({
-  device_name: 'AI-Light',
+  device_name: 'AI-Beacon-Light',
   service_uuid: DEFAULT_SERVICE_UUID,
   mode_char_uuid: DEFAULT_MODE_CHAR_UUID,
   config_char_uuid: DEFAULT_CONFIG_CHAR_UUID,
@@ -54,7 +54,7 @@ function openModal(record?: BleConfig) {
     form.enabled = record.enabled
   } else {
     editingId.value = null
-    form.device_name = 'AI-Light'
+    form.device_name = 'AI-Beacon-Light'
     form.service_uuid = DEFAULT_SERVICE_UUID
     form.mode_char_uuid = DEFAULT_MODE_CHAR_UUID
     form.config_char_uuid = DEFAULT_CONFIG_CHAR_UUID
@@ -164,7 +164,7 @@ onUnmounted(() => window.removeEventListener('resize', onResize))
     >
       <a-form layout="vertical">
         <a-form-item label="设备名称" required>
-          <a-input v-model:value="form.device_name" placeholder="AI-Light" />
+          <a-input v-model:value="form.device_name" placeholder="AI-Beacon-Light / AI-Traffic-Light"/>
         </a-form-item>
         <a-form-item label="Service UUID" required>
           <a-input v-model:value="form.service_uuid" :placeholder="DEFAULT_SERVICE_UUID" />

+ 93 - 52
src/views/DeviceConfig.vue

@@ -1,5 +1,5 @@
 <script lang="ts" setup>
-import {onMounted, reactive, ref, watch} from 'vue'
+import {computed, onMounted, reactive, ref, watch} from 'vue'
 import {message} from 'ant-design-vue'
 import {ClearOutlined, LoadingOutlined, ReloadOutlined, SaveOutlined,} from '@ant-design/icons-vue'
 import {useBleDevice} from '@/composables/useBleDevice'
@@ -47,17 +47,68 @@ function onTabChange(key: string) {
   activeTab.value = key
 }
 
-const LIGHT_MODES = [
-  {key: 'traffic', label: 'Traffic'},
-  {key: 'thinking', label: 'Thinking'},
-  {key: 'ai', label: 'AI'},
-  {key: 'busy', label: 'Busy'},
-  {key: 'success', label: 'Success'},
-  {key: 'error', label: 'Error'},
-  {key: 'alarm', label: 'Alarm'},
-  {key: 'init', label: 'Init'},
-  {key: 'off', label: 'Off'},
-]
+const DEVICE_CONFIGS: Record<string, {
+  modes: { key: string; label: string }[];
+  pins: { key: string; label: string }[]
+}> = {
+  'AI-Beacon-Light': {
+    modes: [
+      {key: 'red', label: 'Red'},
+      {key: 'green', label: 'Green'},
+      {key: 'blue', label: 'Blue'},
+      {key: 'thinking', label: 'Thinking'},
+      {key: 'ai', label: 'AI'},
+      {key: 'busy', label: 'Busy'},
+      {key: 'success', label: 'Success'},
+      {key: 'error', label: 'Error'},
+      {key: 'alarm', label: 'Alarm'},
+      {key: 'init', label: 'Init'},
+      {key: 'off', label: 'Off'},
+    ],
+    pins: [
+      {key: 'red', label: '红灯引脚'},
+      {key: 'green', label: '绿灯引脚'},
+      {key: 'blue', label: '蓝灯引脚'},
+    ],
+  },
+  'AI-Traffic-Light': {
+    modes: [
+      {key: 'traffic', label: 'Traffic'},
+      {key: 'red', label: 'Red'},
+      {key: 'yellow', label: 'Yellow'},
+      {key: 'green', label: 'Green'},
+      {key: 'thinking', label: 'Thinking'},
+      {key: 'ai', label: 'AI'},
+      {key: 'busy', label: 'Busy'},
+      {key: 'success', label: 'Success'},
+      {key: 'error', label: 'Error'},
+      {key: 'alarm', label: 'Alarm'},
+      {key: 'init', label: 'Init'},
+      {key: 'off', label: 'Off'},
+    ],
+    pins: [
+      {key: 'red', label: '红灯引脚'},
+      {key: 'green', label: '绿灯引脚'},
+      {key: 'yellow', label: '黄灯引脚'},
+    ],
+  },
+}
+
+const DEFAULT_DEVICE = 'AI-Beacon-Light'
+
+function getDeviceType(name: string): string {
+  if (name.includes('Traffic')) return 'AI-Traffic-Light'
+  return 'AI-Beacon-Light'
+}
+
+const bleDeviceType = computed(() => getDeviceType(bleName.value))
+const mqttDeviceType = computed(() => getDeviceType(mqttName.value))
+
+const bleLightModes = computed(() => DEVICE_CONFIGS[bleDeviceType.value]?.modes || DEVICE_CONFIGS[DEFAULT_DEVICE].modes)
+const mqttLightModes = computed(() => DEVICE_CONFIGS[mqttDeviceType.value]?.modes || DEVICE_CONFIGS[DEFAULT_DEVICE].modes)
+
+const blePinConfig = computed(() => DEVICE_CONFIGS[bleDeviceType.value]?.pins || DEVICE_CONFIGS[DEFAULT_DEVICE].pins)
+const mqttPinConfig = computed(() => DEVICE_CONFIGS[mqttDeviceType.value]?.pins || DEVICE_CONFIGS[DEFAULT_DEVICE].pins)
 
 const GPIO_OPTIONS = [
   {value: 2, label: 'GPIO2'},
@@ -69,41 +120,42 @@ const bleWifiForm = reactive({ssid: '', password: ''})
 const bleMqttForm = reactive({
   broker: '',
   port: 1883,
-  client: 'AI-Light',
+  client: 'AI-Beacon-Light',
   username: '',
   password: '',
   topic: 'agent/status',
   statusTopic: 'openCodeLight/status',
   topicConfig: 'agent/status/config',
 })
-const blePinForm = reactive({red: 4, green: 3, yellow: 2})
+const blePinForm = reactive<Record<string, number>>({red: 4, green: 3, blue: 2, yellow: 2})
 let blePendingAction: 'save' | 'restart' | null = null
 
 const mqttWifiForm = reactive({ssid: '', password: ''})
 const mqttMqttForm = reactive({
   broker: '',
   port: 1883,
-  client: 'AI-Light',
+  client: 'AI-Beacon-Light',
   username: '',
   password: '',
   topic: 'agent/status',
   statusTopic: 'openCodeLight/status',
   topicConfig: 'agent/status/config',
 })
-const mqttPinForm = reactive({red: 4, green: 3, yellow: 2})
+const mqttPinForm = reactive<Record<string, number>>({red: 4, green: 3, blue: 2, yellow: 2})
 
 watch(bleConfig, (cfg) => {
   if (cfg) {
     bleWifiForm.ssid = cfg.wifi_ssid || ''
     bleMqttForm.broker = cfg.mqtt_broker || ''
     bleMqttForm.port = cfg.mqtt_port || 1883
-    bleMqttForm.client = cfg.mqtt_client || 'AI-Light'
+    bleMqttForm.client = cfg.mqtt_client || 'AI-Beacon-Light'
     bleMqttForm.username = cfg.mqtt_user || ''
     bleMqttForm.topic = cfg.mqtt_topic || ''
     bleMqttForm.statusTopic = cfg.mqtt_status || ''
     bleMqttForm.topicConfig = cfg.mqtt_topic_config || 'agent/status/config'
     blePinForm.red = cfg.pin_red ?? 4
     blePinForm.green = cfg.pin_green ?? 3
+    blePinForm.blue = cfg.pin_blue ?? 2
     blePinForm.yellow = cfg.pin_yellow ?? 2
   }
 })
@@ -124,19 +176,20 @@ watch(mqttConfig, (cfg) => {
     mqttWifiForm.ssid = cfg.wifi_ssid || ''
     mqttMqttForm.broker = cfg.mqtt_broker || ''
     mqttMqttForm.port = cfg.mqtt_port || 1883
-    mqttMqttForm.client = cfg.mqtt_client || 'AI-Light'
+    mqttMqttForm.client = cfg.mqtt_client || 'AI-Beacon-Light'
     mqttMqttForm.username = cfg.mqtt_user || ''
     mqttMqttForm.topic = cfg.mqtt_topic || ''
     mqttMqttForm.statusTopic = cfg.mqtt_status || ''
     mqttMqttForm.topicConfig = cfg.config_topic || 'agent/status/config'
     mqttPinForm.red = cfg.pin_red ?? 4
     mqttPinForm.green = cfg.pin_green ?? 3
+    mqttPinForm.blue = cfg.pin_blue ?? 2
     mqttPinForm.yellow = cfg.pin_yellow ?? 2
   }
 })
 
 async function handleBleSave() {
-  const cfg = {
+  const cfg: Record<string, any> = {
     wifi_ssid: bleWifiForm.ssid,
     wifi_pass: bleWifiForm.password,
     mqtt_broker: bleMqttForm.broker,
@@ -149,7 +202,11 @@ async function handleBleSave() {
     mqtt_topic_config: bleMqttForm.topicConfig,
     pin_red: blePinForm.red,
     pin_green: blePinForm.green,
-    pin_yellow: blePinForm.yellow,
+  }
+  if (bleDeviceType.value === 'AI-Beacon-Light') {
+    cfg.pin_blue = blePinForm.blue
+  } else {
+    cfg.pin_yellow = blePinForm.yellow
   }
   try {
     blePendingAction = 'save'
@@ -171,7 +228,7 @@ async function handleBleRestart() {
 }
 
 async function handleMqttSave() {
-  const cfg = {
+  const cfg: Record<string, any> = {
     wifi_ssid: mqttWifiForm.ssid,
     wifi_pass: mqttWifiForm.password,
     mqtt_broker: mqttMqttForm.broker,
@@ -184,7 +241,11 @@ async function handleMqttSave() {
     mqtt_topic_config: mqttMqttForm.topicConfig,
     pin_red: mqttPinForm.red,
     pin_green: mqttPinForm.green,
-    pin_yellow: mqttPinForm.yellow,
+  }
+  if (mqttDeviceType.value === 'AI-Beacon-Light') {
+    cfg.pin_blue = mqttPinForm.blue
+  } else {
+    cfg.pin_yellow = mqttPinForm.yellow
   }
   try {
     await mqttSaveConfig(cfg)
@@ -285,7 +346,7 @@ onMounted(() => window.addEventListener('resize', onResize))
                 <a-card class="section-card equal-height-card" size="small" title="灯效模式">
                   <div class="mode-grid">
                     <a-button
-                        v-for="m in LIGHT_MODES"
+                        v-for="m in bleLightModes"
                         :key="m.key"
                         :type="bleMode === m.key ? 'primary' : 'default'"
                         class="mode-btn"
@@ -332,7 +393,7 @@ onMounted(() => window.addEventListener('resize', onResize))
                   </a-col>
                   <a-col :span="12">
                     <a-form-item label="客户端ID">
-                      <a-input v-model:value="bleMqttForm.client" placeholder="AI-Light"/>
+                      <a-input v-model:value="bleMqttForm.client" placeholder="AI-Beacon-Light"/>
                     </a-form-item>
                   </a-col>
                 </a-row>
@@ -366,19 +427,9 @@ onMounted(() => window.addEventListener('resize', onResize))
             <a-card class="section-card" size="small" title="灯序配置">
               <a-form layout="vertical">
                 <a-row :gutter="12">
-                  <a-col :span="8">
-                    <a-form-item label="红灯引脚">
-                      <a-select v-model:value="blePinForm.red" :options="GPIO_OPTIONS" style="width: 100%"/>
-                    </a-form-item>
-                  </a-col>
-                  <a-col :span="8">
-                    <a-form-item label="绿灯引脚">
-                      <a-select v-model:value="blePinForm.green" :options="GPIO_OPTIONS" style="width: 100%"/>
-                    </a-form-item>
-                  </a-col>
-                  <a-col :span="8">
-                    <a-form-item label="黄灯引脚">
-                      <a-select v-model:value="blePinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
+                  <a-col v-for="pin in blePinConfig" :key="pin.key" :span="8">
+                    <a-form-item :label="pin.label">
+                      <a-select v-model:value="blePinForm[pin.key]" :options="GPIO_OPTIONS" style="width: 100%"/>
                     </a-form-item>
                   </a-col>
                 </a-row>
@@ -511,7 +562,7 @@ onMounted(() => window.addEventListener('resize', onResize))
                 <a-card class="section-card equal-height-card" size="small" title="灯效模式">
                   <div class="mode-grid">
                     <a-button
-                        v-for="m in LIGHT_MODES"
+                        v-for="m in mqttLightModes"
                         :key="m.key"
                         :type="mqttMode === m.key ? 'primary' : 'default'"
                         class="mode-btn"
@@ -558,7 +609,7 @@ onMounted(() => window.addEventListener('resize', onResize))
                   </a-col>
                   <a-col :span="12">
                     <a-form-item label="客户端ID">
-                      <a-input v-model:value="mqttMqttForm.client" placeholder="AI-Light"/>
+                      <a-input v-model:value="mqttMqttForm.client" placeholder="AI-Beacon-Light"/>
                     </a-form-item>
                   </a-col>
                 </a-row>
@@ -592,19 +643,9 @@ onMounted(() => window.addEventListener('resize', onResize))
             <a-card class="section-card" size="small" title="灯序配置">
               <a-form layout="vertical">
                 <a-row :gutter="12">
-                  <a-col :span="8">
-                    <a-form-item label="红灯引脚">
-                      <a-select v-model:value="mqttPinForm.red" :options="GPIO_OPTIONS" style="width: 100%"/>
-                    </a-form-item>
-                  </a-col>
-                  <a-col :span="8">
-                    <a-form-item label="绿灯引脚">
-                      <a-select v-model:value="mqttPinForm.green" :options="GPIO_OPTIONS" style="width: 100%"/>
-                    </a-form-item>
-                  </a-col>
-                  <a-col :span="8">
-                    <a-form-item label="黄灯引脚">
-                      <a-select v-model:value="mqttPinForm.yellow" :options="GPIO_OPTIONS" style="width: 100%"/>
+                  <a-col v-for="pin in mqttPinConfig" :key="pin.key" :span="8">
+                    <a-form-item :label="pin.label">
+                      <a-select v-model:value="mqttPinForm[pin.key]" :options="GPIO_OPTIONS" style="width: 100%"/>
                     </a-form-item>
                   </a-col>
                 </a-row>

+ 3 - 3
src/views/ServerConfig.vue

@@ -32,7 +32,7 @@ const DEFAULT_MODE_CHAR_UUID = 'b8b7e002-7a6b-4f4f-9a8b-11c0ffee0001'
 const DEFAULT_CONFIG_CHAR_UUID = 'b8b7e003-7a6b-4f4f-9a8b-11c0ffee0001'
 
 const bleForm = reactive<BleConfigForm>({
-  device_name: 'AI-Light',
+  device_name: 'AI-Beacon-Light',
   service_uuid: DEFAULT_SERVICE_UUID,
   mode_char_uuid: DEFAULT_MODE_CHAR_UUID,
   config_char_uuid: DEFAULT_CONFIG_CHAR_UUID,
@@ -129,7 +129,7 @@ function openBleModal(record?: BleConfig) {
     bleForm.enabled = record.enabled
   } else {
     bleEditingId.value = null
-    bleForm.device_name = 'AI-Light'
+    bleForm.device_name = 'AI-Beacon-Light'
     bleForm.service_uuid = DEFAULT_SERVICE_UUID
     bleForm.mode_char_uuid = DEFAULT_MODE_CHAR_UUID
     bleForm.config_char_uuid = DEFAULT_CONFIG_CHAR_UUID
@@ -344,7 +344,7 @@ onMounted(() => {
     >
       <a-form layout="vertical">
         <a-form-item label="设备名称" required>
-          <a-input v-model:value="bleForm.device_name" placeholder="AI-Light"/>
+          <a-input v-model:value="bleForm.device_name" placeholder="AI-Beacon-Light / AI-Traffic-Light"/>
         </a-form-item>
         <a-form-item label="服务码" required>
           <a-input v-model:value="bleForm.service_uuid" :placeholder="DEFAULT_SERVICE_UUID"/>