当前位置: 首页 > news >正文

网站续费服务内容国外的建筑设计案例网站

网站续费服务内容,国外的建筑设计案例网站,网站域名空间租用合同,西安东郊网站建设1. 引言 随着物联网技术的快速发展#xff0c;智能家居系统已经成为现代家庭生活的重要组成部分。本文将详细介绍一个基于Python的智能家居控制系统的设计与实现过程#xff0c;该系统能够实现对家庭设备的集中管理和智能控制#xff0c;提升家居生活的便捷性和舒适度。 2…1. 引言 随着物联网技术的快速发展智能家居系统已经成为现代家庭生活的重要组成部分。本文将详细介绍一个基于Python的智能家居控制系统的设计与实现过程该系统能够实现对家庭设备的集中管理和智能控制提升家居生活的便捷性和舒适度。 2. 系统架构设计 2.1 总体架构 智能家居控制系统采用分层架构设计主要包括以下几个层次 设备层各种智能家居设备如灯光、空调、窗帘、安防设备等通信层负责设备与控制中心之间的数据传输支持WiFi、蓝牙、Zigbee等多种通信协议控制层系统的核心处理来自用户的指令并转发给相应的设备应用层提供Web界面和移动应用供用户进行交互操作智能层基于机器学习算法实现系统的自动化决策和智能场景控制 2.2 核心模块设计 系统主要包含以下核心模块 设备管理模块负责设备的注册、状态监控和控制用户管理模块处理用户认证、权限管理等功能场景控制模块实现自定义场景的创建和执行数据分析模块收集和分析用户行为数据为智能决策提供支持API接口模块提供RESTful API支持第三方应用集成 3. 技术选型 3.1 编程语言与框架 后端Python 3.9Web框架Flask 2.0.1WebSocketFlask-SocketIO数据库SQLite开发环境/ PostgreSQL生产环境ORMSQLAlchemy前端HTML5 CSS3 JavaScript前端框架Vue.js 3.0UI组件库Element Plus 3.2 硬件通信技术 WiFi通信使用MQTT协议蓝牙通信使用PyBluez库Zigbee通信通过串口与Zigbee协调器通信 3.3 智能算法 用户行为分析基于Scikit-learn的聚类算法场景推荐基于协同过滤的推荐算法异常检测基于统计和机器学习的异常检测算法 4. 系统实现 4.1 设备管理模块实现 设备管理是系统的基础模块负责管理所有智能设备。以下是设备基类的实现 # device_manager.py from abc import ABC, abstractmethod import uuid import timeclass Device(ABC):智能设备基类def __init__(self, name, location, device_type):self.device_id str(uuid.uuid4())self.name nameself.location locationself.type device_typeself.status offlineself.last_updated time.time()abstractmethoddef turn_on(self):passabstractmethoddef turn_off(self):passdef get_status(self):return {device_id: self.device_id,name: self.name,location: self.location,type: self.type,status: self.status,last_updated: self.last_updated}def update_status(self, status):self.status statusself.last_updated time.time()class LightDevice(Device):灯光设备类def __init__(self, name, location, brightness100):super().__init__(name, location, light)self.brightness brightnessself.color whitedef turn_on(self):self.update_status(on)return Truedef turn_off(self):self.update_status(off)return Truedef set_brightness(self, brightness):if 0 brightness 100:self.brightness brightnessreturn Truereturn Falsedef set_color(self, color):self.color colorreturn Truedef get_status(self):status super().get_status()status.update({brightness: self.brightness,color: self.color})return statusclass DeviceManager:设备管理器def __init__(self):self.devices {}def add_device(self, device):self.devices[device.device_id] devicereturn device.device_iddef remove_device(self, device_id):if device_id in self.devices:del self.devices[device_id]return Truereturn Falsedef get_device(self, device_id):return self.devices.get(device_id)def get_all_devices(self):return [device.get_status() for device in self.devices.values()]def get_devices_by_type(self, device_type):return [device.get_status() for device in self.devices.values() if device.type device_type]def get_devices_by_location(self, location):return [device.get_status() for device in self.devices.values() if device.location location]4.2 场景控制模块实现 场景控制模块允许用户创建自定义场景实现多设备的联动控制 # scene_controller.py import time import jsonclass Scene:场景类def __init__(self, name, description):self.scene_id str(uuid.uuid4())self.name nameself.description descriptionself.actions []self.created_at time.time()self.last_executed Nonedef add_action(self, device_id, action, paramsNone):if params is None:params {}self.actions.append({device_id: device_id,action: action,params: params})def remove_action(self, index):if 0 index len(self.actions):self.actions.pop(index)return Truereturn Falsedef get_details(self):return {scene_id: self.scene_id,name: self.name,description: self.description,actions: self.actions,created_at: self.created_at,last_executed: self.last_executed}class SceneController:场景控制器def __init__(self, device_manager):self.scenes {}self.device_manager device_managerdef create_scene(self, name, description):scene Scene(name, description)self.scenes[scene.scene_id] scenereturn scene.scene_iddef delete_scene(self, scene_id):if scene_id in self.scenes:del self.scenes[scene_id]return Truereturn Falsedef get_scene(self, scene_id):return self.scenes.get(scene_id)def get_all_scenes(self):return [scene.get_details() for scene in self.scenes.values()]def execute_scene(self, scene_id):scene self.scenes.get(scene_id)if not scene:return Falseresults []for action in scene.actions:device self.device_manager.get_device(action[device_id])if device:if action[action] turn_on:result device.turn_on()elif action[action] turn_off:result device.turn_off()elif action[action] set_brightness and hasattr(device, set_brightness):result device.set_brightness(action[params].get(brightness, 100))elif action[action] set_color and hasattr(device, set_color):result device.set_color(action[params].get(color, white))else:result Falseresults.append({device_id: action[device_id],action: action[action],success: result})scene.last_executed time.time()return results 4.3 API接口实现 使用Flask框架实现RESTful API接口 # app.py from flask import Flask, request, jsonify from flask_socketio import SocketIO from device_manager import DeviceManager, LightDevice from scene_controller import SceneController import jsonapp Flask(__name__) socketio SocketIO(app, cors_allowed_origins*)# 初始化设备管理器和场景控制器 device_manager DeviceManager() scene_controller SceneController(device_manager)# 设备管理API app.route(/api/devices, methods[GET]) def get_devices():return jsonify(device_manager.get_all_devices())app.route(/api/devices, methods[POST]) def add_device():data request.jsonif data.get(type) light:device LightDevice(namedata.get(name, New Light),locationdata.get(location, Living Room),brightnessdata.get(brightness, 100))device_id device_manager.add_device(device)return jsonify({device_id: device_id}), 201return jsonify({error: Unsupported device type}), 400app.route(/api/devices/device_id, methods[GET]) def get_device(device_id):device device_manager.get_device(device_id)if device:return jsonify(device.get_status())return jsonify({error: Device not found}), 404app.route(/api/devices/device_id/control, methods[POST]) def control_device(device_id):device device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404data request.jsonaction data.get(action)if action turn_on:result device.turn_on()elif action turn_off:result device.turn_off()elif action set_brightness and hasattr(device, set_brightness):result device.set_brightness(data.get(brightness, 100))elif action set_color and hasattr(device, set_color):result device.set_color(data.get(color, white))else:return jsonify({error: Invalid action}), 400# 通过WebSocket广播设备状态变化socketio.emit(device_update, device.get_status())return jsonify({success: result})# 场景管理API app.route(/api/scenes, methods[GET]) def get_scenes():return jsonify(scene_controller.get_all_scenes())app.route(/api/scenes, methods[POST]) def create_scene():data request.jsonscene_id scene_controller.create_scene(namedata.get(name, New Scene),descriptiondata.get(description, ))# 添加场景动作scene scene_controller.get_scene(scene_id)for action in data.get(actions, []):scene.add_action(device_idaction.get(device_id),actionaction.get(action),paramsaction.get(params, {}))return jsonify({scene_id: scene_id}), 201app.route(/api/scenes/scene_id/execute, methods[POST]) def execute_scene(scene_id):results scene_controller.execute_scene(scene_id)if results is False:return jsonify({error: Scene not found}), 404return jsonify({results: results})# 主程序入口 if __name__ __main__:# 添加一些测试设备living_room_light LightDevice(客厅主灯, 客厅)bedroom_light LightDevice(卧室灯, 卧室)device_manager.add_device(living_room_light)device_manager.add_device(bedroom_light)# 创建一个测试场景night_mode_id scene_controller.create_scene(夜间模式, 睡前自动设置的场景)night_mode scene_controller.get_scene(night_mode_id)night_mode.add_action(living_room_light.device_id, turn_off)night_mode.add_action(bedroom_light.device_id, set_brightness, {brightness: 30})# 启动服务器socketio.run(app, host0.0.0.0, port5000, debugTrue)4.4 前端界面实现 使用Vue.js和Element Plus构建用户界面 !-- static/index.html -- !DOCTYPE html html langzh-CN headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title智能家居控制系统/titlelink relstylesheet hrefhttps://unpkg.com/element-plus/dist/index.csslink relstylesheet href/static/css/style.css /head bodydiv idappel-containerel-headerh1智能家居控制系统/h1/el-headerel-containerel-aside width250pxel-menu default-activedevicesel-menu-item indexdevices clickactiveTab devicesi classel-icon-cpu/ispan设备管理/span/el-menu-itemel-menu-item indexscenes clickactiveTab scenesi classel-icon-magic-stick/ispan场景控制/span/el-menu-itemel-menu-item indexstatistics clickactiveTab statisticsi classel-icon-data-line/ispan数据统计/span/el-menu-itemel-menu-item indexsettings clickactiveTab settingsi classel-icon-setting/ispan系统设置/span/el-menu-item/el-menu/el-asideel-main!-- 设备管理页面 --div v-ifactiveTab devicesel-row :gutter20el-col :span24el-cardtemplate #headerdiv classcard-headerspan设备列表/spanel-button typeprimary sizesmall clickshowAddDeviceDialog添加设备/el-button/div/templateel-table :datadevices stylewidth: 100%el-table-column propname label设备名称/el-table-columnel-table-column proplocation label位置/el-table-columnel-table-column proptype label类型/el-table-columnel-table-column propstatus label状态template #defaultscopeel-tag :typescope.row.status on ? success : info{{ scope.row.status on ? 开启 : 关闭 }}/el-tag/template/el-table-columnel-table-column label操作template #defaultscopeel-button sizesmall :typescope.row.status on ? danger : successclickcontrolDevice(scope.row.device_id, scope.row.status on ? turn_off : turn_on){{ scope.row.status on ? 关闭 : 开启 }}/el-buttonel-button sizesmall typeprimary clickshowDeviceDetailDialog(scope.row)详情/el-button/template/el-table-column/el-table/el-card/el-col/el-row/div!-- 场景控制页面 --div v-ifactiveTab scenesel-row :gutter20el-col :span24el-cardtemplate #headerdiv classcard-headerspan场景列表/spanel-button typeprimary sizesmall clickshowAddSceneDialog创建场景/el-button/div/templateel-table :datascenes stylewidth: 100%el-table-column propname label场景名称/el-table-columnel-table-column propdescription label描述/el-table-columnel-table-column label操作template #defaultscopeel-button sizesmall typesuccessclickexecuteScene(scope.row.scene_id)执行/el-buttonel-button sizesmall typeprimary clickshowSceneDetailDialog(scope.row)详情/el-button/template/el-table-column/el-table/el-card/el-col/el-row/div/el-main/el-container/el-container!-- 添加设备对话框 --el-dialog title添加设备 v-modeladdDeviceDialogVisibleel-form :modelnewDevice label-width100pxel-form-item label设备名称el-input v-modelnewDevice.name/el-input/el-form-itemel-form-item label位置el-input v-modelnewDevice.location/el-input/el-form-itemel-form-item label设备类型el-select v-modelnewDevice.type placeholder请选择设备类型el-option label灯光 valuelight/el-optionel-option label空调 valueac disabled/el-optionel-option label窗帘 valuecurtain disabled/el-option/el-select/el-form-item/el-formtemplate #footerspan classdialog-footerel-button clickaddDeviceDialogVisible false取消/el-buttonel-button typeprimary clickaddDevice确定/el-button/span/template/el-dialog/divscript srchttps://unpkg.com/vuenext/scriptscript srchttps://unpkg.com/element-plus/scriptscript srchttps://unpkg.com/axios/dist/axios.min.js/scriptscript srchttps://cdn.socket.io/4.4.1/socket.io.min.js/scriptscript src/static/js/app.js/script /body /html// static/js/app.js const { createApp, ref, onMounted } Vue;const app createApp({setup() {const activeTab ref(devices);const devices ref([]);const scenes ref([]);const addDeviceDialogVisible ref(false);const newDevice ref({name: ,location: ,type: light});// 初始化WebSocket连接const socket io();// 监听设备状态更新socket.on(device_update, (data) {const index devices.value.findIndex(d d.device_id data.device_id);if (index ! -1) {devices.value[index] data;}});// 获取所有设备const fetchDevices async () {try {const response await axios.get(/api/devices);devices.value response.data;} catch (error) {console.error(获取设备列表失败:, error);ElMessage.error(获取设备列表失败);}};// 获取所有场景const fetchScenes async () {try {const response await axios.get(/api/scenes);scenes.value response.data;} catch (error) {console.error(获取场景列表失败:, error);ElMessage.error(获取场景列表失败);}};// 控制设备const controlDevice async (deviceId, action, params {}) {try {await axios.post(/api/devices/${deviceId}/control, {action,...params});ElMessage.success(设备操作成功: ${action});} catch (error) {console.error(设备操作失败:, error);ElMessage.error(设备操作失败);}};// 执行场景const executeScene async (sceneId) {try {const response await axios.post(/api/scenes/${sceneId}/execute);ElMessage.success(场景执行成功);} catch (error) {console.error(场景执行失败:, error);ElMessage.error(场景执行失败);}};// 添加设备const addDevice async () {try {await axios.post(/api/devices, newDevice.value);ElMessage.success(设备添加成功);addDeviceDialogVisible.value false;fetchDevices();// 重置表单newDevice.value {name: ,location: ,type: light};} catch (error) {console.error(添加设备失败:, error);ElMessage.error(添加设备失败);}};// 显示添加设备对话框const showAddDeviceDialog () {addDeviceDialogVisible.value true;};// 显示设备详情对话框const showDeviceDetailDialog (device) {// 实现详情对话框逻辑console.log(设备详情:, device);};// 显示添加场景对话框const showAddSceneDialog () {// 实现添加场景对话框逻辑console.log(添加场景);};// 显示场景详情对话框const showSceneDetailDialog (scene) {// 实现场景详情对话框逻辑console.log(场景详情:, scene);};// 页面加载时获取数据onMounted(() {fetchDevices();fetchScenes();});return {activeTab,devices,scenes,addDeviceDialogVisible,newDevice,controlDevice,executeScene,addDevice,showAddDeviceDialog,showDeviceDetailDialog,showAddSceneDialog,showSceneDetailDialog};} });app.use(ElementPlus); app.mount(#app);5. 系统测试 5.1 单元测试 使用Python的unittest框架对各个模块进行单元测试 # tests/test_device_manager.py import unittest from device_manager import DeviceManager, LightDeviceclass TestDeviceManager(unittest.TestCase):def setUp(self):self.device_manager DeviceManager()self.light LightDevice(测试灯, 测试房间)def test_add_device(self):device_id self.device_manager.add_device(self.light)self.assertIsNotNone(device_id)self.assertEqual(len(self.device_manager.devices), 1)def test_get_device(self):device_id self.device_manager.add_device(self.light)device self.device_manager.get_device(device_id)self.assertEqual(device, self.light)def test_remove_device(self):device_id self.device_manager.add_device(self.light)result self.device_manager.remove_device(device_id)self.assertTrue(result)self.assertEqual(len(self.device_manager.devices), 0)def test_get_all_devices(self):self.device_manager.add_device(self.light)devices self.device_manager.get_all_devices()self.assertEqual(len(devices), 1)self.assertEqual(devices[0][name], 测试灯)def test_light_device_functions(self):self.light.turn_on()self.assertEqual(self.light.status, on)self.light.set_brightness(50)self.assertEqual(self.light.brightness, 50)self.light.set_color(blue)self.assertEqual(self.light.color, blue)self.light.turn_off()self.assertEqual(self.light.status, off)if __name__ __main__:unittest.main()6. 系统扩展与优化 6.1 安全性增强 用户认证与授权实现JWT认证机制确保API接口的安全访问 HTTPS支持配置SSL证书启用HTTPS加密通信 设备通信加密对设备与控制中心之间的通信进行加密 日志审计记录所有关键操作便于安全审计 6.2 功能扩展 语音控制集成语音识别模块支持语音指令控制 移动应用开发配套的移动应用实现随时随地控制 智能算法优化引入更先进的机器学习算法提升系统智能化水平 多协议支持扩展对更多设备通信协议的支持如Z-Wave、KNX等 6.3 性能优化 异步处理使用异步框架处理设备通信提高系统响应速度 缓存机制引入Redis缓存减轻数据库负担 分布式部署实现系统的分布式部署提高可扩展性和可用性 微服务架构将系统拆分为多个微服务便于独立扩展和维护 7. 总结与展望 本文详细介绍了一个基于Python的智能家居控制系统的设计与实现过程。该系统采用分层架构设计实现了设备管理、场景控制、用户界面等核心功能并通过多种通信协议支持各类智能设备的接入和控制。 系统的主要特点包括 模块化设计系统各模块职责明确便于扩展和维护 多协议支持支持WiFi、蓝牙、Zigbee等多种通信协议 智能化控制基于机器学习算法实现智能场景推荐和自动化控制 友好的用户界面提供Web界面和移动应用操作简单直观 未来系统可以在以下方面进行进一步的发展 边缘计算将部分计算任务下放到边缘设备减轻中心服务器负担 AI增强引入深度学习和强化学习算法提升系统智能化水平 生态系统集成与主流智能家居生态系统如Apple HomeKit、Google Home、Amazon Alexa等进行集成 能源管理增加能源消耗监控和优化功能实现绿色节能 智能家居作为物联网的重要应用场景将随着技术的发展不断演进。本系统为智能家居的实现提供了一种可行的解决方案希望能为相关领域的研究和实践提供参考。 源代码 Directory Content Summary Source Directory: ./smart_home_system Directory Structure smart_home_system/README.mdrequirements.txtrun.pyapp/database.pydevice_manager.pyscene_manager.py__init__.pyroutes/api.py__init__.pyconfig/static/css/styles.cssjs/app.jstemplates/index.htmlFile Contents README.md # 智能家居控制系统这是一个基于Python的智能家居控制系统实现了对家庭设备的集中管理和智能控制。## 功能特点- 设备管理添加、编辑、删除和控制各种智能设备 - 位置管理管理设备所在的位置 - 数据统计查看设备状态和分布统计 - 设备历史记录设备状态变化历史 - 响应式界面适配不同尺寸的屏幕## 支持的设备类型- 灯光设备控制开关、亮度和颜色 - 温控设备控制温度和工作模式## 技术栈### 后端 - Python 3.9 - Flask Web框架 - SQLite数据库### 前端 - Vue.js 3 - Bootstrap 5 - Axios HTTP客户端## 安装与运行1. 克隆或下载项目代码2. 安装依赖 bash pip install -r requirements.txt 运行应用 python run.py 在浏览器中访问 http://localhost:5000 项目结构 smart_home_system/ ├── app/ # 应用代码 │ ├── __init__.py # 应用初始化 │ ├── database.py # 数据库模块 │ ├── device_manager.py # 设备管理模块 │ └── routes/ # API路由 │ ├── __init__.py │ └── api.py # API接口定义 ├── config/ # 配置文件 ├── static/ # 静态资源 │ ├── css/ # CSS样式 │ │ └── styles.css # 主样式表 │ └── js/ # JavaScript代码 │ └── app.js # 前端应用 ├── templates/ # HTML模板 │ └── index.html # 主页面 ├── README.md # 项目说明 ├── requirements.txt # 依赖列表 └── run.py # 应用入口 API接口 设备管理 GET /api/devices - 获取所有设备 GET /api/devices/device_id - 获取单个设备 POST /api/devices - 添加设备 PUT /api/devices/device_id - 更新设备 DELETE /api/devices/device_id - 删除设备 POST /api/devices/device_id/control - 控制设备 GET /api/devices/device_id/history - 获取设备历史 位置管理 GET /api/locations - 获取所有位置 POST /api/locations - 添加位置 设备类型 GET /api/device-types - 获取所有设备类型 扩展与自定义 添加新设备类型 在 device_manager.py 中创建新的设备类型类继承 DeviceType 基类 实现必要的方法create_device, get_properties_schema, validate_command, execute_command 在 DeviceFactory 中注册新设备类型 自定义数据库 默认使用SQLite数据库如需使用其他数据库修改 database.py 中的数据库连接和操作代码 更新 requirements.txt 添加相应的数据库驱动 requirements.txt Flask2.2.3 Flask-Cors3.0.10 Werkzeug2.2.3 Jinja23.1.2 MarkupSafe2.1.2 itsdangerous2.1.2 click8.1.3 colorama0.4.6 5. README Filerun.py Main entry point for Smart Home Systemfrom app import create_appapp create_app()if __name__ __main__:app.run(host0.0.0.0, port5000, debugTrue)app\database.py Database module for Smart Home System Handles database operations for device managementimport sqlite3 import json import os import datetime from pathlib import Pathclass Database:def __init__(self, db_pathNone):Initialize database connectionif db_path is None:# Create database in the project directorybase_dir Path(__file__).resolve().parent.parentdb_path os.path.join(base_dir, smart_home.db)self.db_path db_pathself.connection Noneself.cursor Noneself._connect()self._create_tables()def _connect(self):Connect to the SQLite databasetry:self.connection sqlite3.connect(self.db_path)self.connection.row_factory sqlite3.Row # Return rows as dictionariesself.cursor self.connection.cursor()except sqlite3.Error as e:print(fDatabase connection error: {e})raisedef _create_tables(self):Create necessary tables if they dont existtry:# Devices tableself.cursor.execute(CREATE TABLE IF NOT EXISTS devices (id TEXT PRIMARY KEY,name TEXT NOT NULL,type TEXT NOT NULL,location TEXT,status TEXT DEFAULT offline,properties TEXT,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP))# Device history table for logging state changesself.cursor.execute(CREATE TABLE IF NOT EXISTS device_history (id INTEGER PRIMARY KEY AUTOINCREMENT,device_id TEXT NOT NULL,status TEXT NOT NULL,properties TEXT,timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY (device_id) REFERENCES devices (id)))# Locations tableself.cursor.execute(CREATE TABLE IF NOT EXISTS locations (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL UNIQUE,description TEXT))# Scenes tableself.cursor.execute(CREATE TABLE IF NOT EXISTS scenes (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL UNIQUE,description TEXT,icon TEXT DEFAULT lightbulb,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP))# Scene actions table - stores device states for each sceneself.cursor.execute(CREATE TABLE IF NOT EXISTS scene_actions (id INTEGER PRIMARY KEY AUTOINCREMENT,scene_id INTEGER NOT NULL,device_id TEXT NOT NULL,action_type TEXT NOT NULL,action_params TEXT,FOREIGN KEY (scene_id) REFERENCES scenes (id) ON DELETE CASCADE,FOREIGN KEY (device_id) REFERENCES devices (id) ON DELETE CASCADE))# Insert default locations if they dont existdefault_locations [Living Room, Bedroom, Kitchen, Bathroom, Office, Hallway]for location in default_locations:self.cursor.execute(INSERT OR IGNORE INTO locations (name) VALUES (?), (location,))self.connection.commit()except sqlite3.Error as e:print(fError creating tables: {e})raisedef close(self):Close the database connectionif self.connection:self.connection.close()# Device operationsdef add_device(self, device_data):Add a new device to the databasetry:# Convert properties dict to JSON stringif properties in device_data and isinstance(device_data[properties], dict):device_data[properties] json.dumps(device_data[properties])# Get current timestampcurrent_time datetime.datetime.now().isoformat()self.cursor.execute(INSERT INTO devices (id, name, type, location, status, properties, created_at, last_updated)VALUES (?, ?, ?, ?, ?, ?, ?, ?), (device_data[id],device_data[name],device_data[type],device_data.get(location, Unknown),device_data.get(status, offline),device_data.get(properties, {}),current_time,current_time))self.connection.commit()return Trueexcept sqlite3.Error as e:print(fError adding device: {e})self.connection.rollback()return Falsedef update_device(self, device_id, update_data):Update device informationtry:# Get current device datacurrent_device self.get_device(device_id)if not current_device:return False# Prepare update fieldsupdate_fields []update_values []for key, value in update_data.items():if key properties and isinstance(value, dict):# Merge with existing propertiescurrent_props json.loads(current_device[properties]) if current_device[properties] else {}current_props.update(value)value json.dumps(current_props)if key in [name, type, location, status, properties]:update_fields.append(f{key} ?)update_values.append(value)# Add last_updated timestampupdate_fields.append(last_updated ?)update_values.append(datetime.datetime.now().isoformat())# Add device_id for WHERE clauseupdate_values.append(device_id)# Execute update queryif update_fields:query fUPDATE devices SET {, .join(update_fields)}WHERE id ?self.cursor.execute(query, update_values)# Log state change if status or properties changedif status in update_data or properties in update_data:self._log_device_history(device_id, update_data.get(status, current_device[status]),update_data.get(properties, current_device[properties]))self.connection.commit()return Truereturn Falseexcept sqlite3.Error as e:print(fError updating device: {e})self.connection.rollback()return Falsedef delete_device(self, device_id):Delete a device from the databasetry:self.cursor.execute(DELETE FROM devices WHERE id ?, (device_id,))self.cursor.execute(DELETE FROM device_history WHERE device_id ?, (device_id,))self.cursor.execute(DELETE FROM scene_actions WHERE device_id ?, (device_id,))self.connection.commit()return Trueexcept sqlite3.Error as e:print(fError deleting device: {e})self.connection.rollback()return Falsedef get_device(self, device_id):Get a device by IDtry:self.cursor.execute(SELECT * FROM devices WHERE id ?, (device_id,))device self.cursor.fetchone()if device:device_dict dict(device)# Parse properties JSONif device_dict[properties]:device_dict[properties] json.loads(device_dict[properties])return device_dictreturn Noneexcept sqlite3.Error as e:print(fError getting device: {e})return Nonedef get_all_devices(self):Get all devicestry:self.cursor.execute(SELECT * FROM devices ORDER BY name)devices self.cursor.fetchall()result []for device in devices:device_dict dict(device)# Parse properties JSONif device_dict[properties]:device_dict[properties] json.loads(device_dict[properties])result.append(device_dict)return resultexcept sqlite3.Error as e:print(fError getting devices: {e})return []def get_devices_by_type(self, device_type):Get devices by typetry:self.cursor.execute(SELECT * FROM devices WHERE type ? ORDER BY name, (device_type,))devices self.cursor.fetchall()result []for device in devices:device_dict dict(device)# Parse properties JSONif device_dict[properties]:device_dict[properties] json.loads(device_dict[properties])result.append(device_dict)return resultexcept sqlite3.Error as e:print(fError getting devices by type: {e})return []def get_devices_by_location(self, location):Get devices by locationtry:self.cursor.execute(SELECT * FROM devices WHERE location ? ORDER BY name, (location,))devices self.cursor.fetchall()result []for device in devices:device_dict dict(device)# Parse properties JSONif device_dict[properties]:device_dict[properties] json.loads(device_dict[properties])result.append(device_dict)return resultexcept sqlite3.Error as e:print(fError getting devices by location: {e})return []def _log_device_history(self, device_id, status, properties):Log device state change to historytry:if isinstance(properties, dict):properties json.dumps(properties)self.cursor.execute(INSERT INTO device_history (device_id, status, properties)VALUES (?, ?, ?), (device_id, status, properties))return Trueexcept sqlite3.Error as e:print(fError logging device history: {e})return Falsedef get_device_history(self, device_id, limit50):Get device historytry:self.cursor.execute(SELECT * FROM device_historyWHERE device_id ?ORDER BY timestamp DESCLIMIT ?, (device_id, limit))history self.cursor.fetchall()result []for entry in history:entry_dict dict(entry)# Parse properties JSONif entry_dict[properties]:entry_dict[properties] json.loads(entry_dict[properties])result.append(entry_dict)return resultexcept sqlite3.Error as e:print(fError getting device history: {e})return []# Location operationsdef get_all_locations(self):Get all locationstry:self.cursor.execute(SELECT * FROM locations ORDER BY name)locations self.cursor.fetchall()return [dict(location) for location in locations]except sqlite3.Error as e:print(fError getting locations: {e})return []def add_location(self, name, descriptionNone):Add a new locationtry:self.cursor.execute(INSERT INTO locations (name, description)VALUES (?, ?), (name, description))self.connection.commit()return self.cursor.lastrowidexcept sqlite3.Error as e:print(fError adding location: {e})self.connection.rollback()return None# Scene operationsdef add_scene(self, scene_data):Add a new scenetry:name scene_data.get(name)description scene_data.get(description)icon scene_data.get(icon, lightbulb)current_time datetime.datetime.now().isoformat()self.cursor.execute(INSERT INTO scenes (name, description, icon, created_at, last_updated)VALUES (?, ?, ?, ?, ?), (name, description, icon, current_time, current_time))scene_id self.cursor.lastrowid# Add scene actions if providedactions scene_data.get(actions, [])for action in actions:self.add_scene_action(scene_id, action)self.connection.commit()return scene_idexcept sqlite3.Error as e:print(fError adding scene: {e})self.connection.rollback()return Nonedef update_scene(self, scene_id, update_data):Update scene informationtry:update_fields []update_values []for key, value in update_data.items():if key in [name, description, icon]:update_fields.append(f{key} ?)update_values.append(value)# Add last_updated timestampupdate_fields.append(last_updated ?)update_values.append(datetime.datetime.now().isoformat())# Add scene_id for WHERE clauseupdate_values.append(scene_id)# Execute update queryif update_fields:query fUPDATE scenes SET {, .join(update_fields)}WHERE id ?self.cursor.execute(query, update_values)# Update scene actions if providedif actions in update_data:# Delete existing actionsself.cursor.execute(DELETE FROM scene_actions WHERE scene_id ?, (scene_id,))# Add new actionsfor action in update_data[actions]:self.add_scene_action(scene_id, action)self.connection.commit()return Truereturn Falseexcept sqlite3.Error as e:print(fError updating scene: {e})self.connection.rollback()return Falsedef delete_scene(self, scene_id):Delete a scenetry:self.cursor.execute(DELETE FROM scenes WHERE id ?, (scene_id,))self.cursor.execute(DELETE FROM scene_actions WHERE scene_id ?, (scene_id,))self.connection.commit()return Trueexcept sqlite3.Error as e:print(fError deleting scene: {e})self.connection.rollback()return Falsedef get_scene(self, scene_id):Get a scene by IDtry:self.cursor.execute(SELECT * FROM scenes WHERE id ?, (scene_id,))scene self.cursor.fetchone()if not scene:return Nonescene_dict dict(scene)# Get scene actionsscene_dict[actions] self.get_scene_actions(scene_id)return scene_dictexcept sqlite3.Error as e:print(fError getting scene: {e})return Nonedef get_all_scenes(self):Get all scenestry:self.cursor.execute(SELECT * FROM scenes ORDER BY name)scenes self.cursor.fetchall()result []for scene in scenes:scene_dict dict(scene)scene_dict[actions] self.get_scene_actions(scene_dict[id])result.append(scene_dict)return resultexcept sqlite3.Error as e:print(fError getting scenes: {e})return []def add_scene_action(self, scene_id, action_data):Add a scene actiontry:device_id action_data.get(device_id)action_type action_data.get(action_type)action_params action_data.get(action_params, {})if isinstance(action_params, dict):action_params json.dumps(action_params)self.cursor.execute(INSERT INTO scene_actions (scene_id, device_id, action_type, action_params)VALUES (?, ?, ?, ?), (scene_id, device_id, action_type, action_params))return self.cursor.lastrowidexcept sqlite3.Error as e:print(fError adding scene action: {e})return Nonedef get_scene_actions(self, scene_id):Get actions for a scenetry:self.cursor.execute(SELECT * FROM scene_actions WHERE scene_id ?, (scene_id,))actions self.cursor.fetchall()result []for action in actions:action_dict dict(action)# Parse action_params JSONif action_dict[action_params]:action_dict[action_params] json.loads(action_dict[action_params])result.append(action_dict)return resultexcept sqlite3.Error as e:print(fError getting scene actions: {e})return []app\device_manager.py Device Manager Module for Smart Home System Handles device operations and communicationimport uuid import time import json from .database import Databaseclass DeviceManager:Device Manager class for handling device operationsdef __init__(self, dbNone):Initialize the device managerself.db db if db else Database()self.devices {} # In-memory cache of devicesself._load_devices_from_db()def _load_devices_from_db(self):Load devices from database into memorydevices self.db.get_all_devices()for device in devices:self.devices[device[id]] devicedef register_device(self, name, device_type, locationNone, propertiesNone):Register a new deviceif properties is None:properties {}device_id str(uuid.uuid4())device_data {id: device_id,name: name,type: device_type,location: location,status: offline,properties: properties}# Add to databaseif self.db.add_device(device_data):# Add to in-memory cacheself.devices[device_id] device_datareturn device_idreturn Nonedef update_device_status(self, device_id, status, propertiesNone):Update device status and propertiesif device_id not in self.devices:return Falseupdate_data {status: status}if properties:update_data[properties] properties# Update databaseif self.db.update_device(device_id, update_data):# Update in-memory cacheself.devices[device_id].update(update_data)self.devices[device_id][last_updated] time.time()return Truereturn Falsedef get_device(self, device_id):Get device by IDif device_id in self.devices:return self.devices[device_id]# Try to get from databasedevice self.db.get_device(device_id)if device:self.devices[device_id] devicereturn devicereturn Nonedef get_all_devices(self):Get all devicesreturn list(self.devices.values())def get_devices_by_type(self, device_type):Get devices by typereturn [device for device in self.devices.values() if device[type] device_type]def get_devices_by_location(self, location):Get devices by locationreturn [device for device in self.devices.values() if device[location] location]def delete_device(self, device_id):Delete a deviceif device_id not in self.devices:return False# Delete from databaseif self.db.delete_device(device_id):# Delete from in-memory cachedel self.devices[device_id]return Truereturn Falsedef update_device_properties(self, device_id, properties):Update device propertiesif device_id not in self.devices:return False# Get current propertiescurrent_props self.devices[device_id].get(properties, {})# Merge with new propertiesif isinstance(properties, dict):current_props.update(properties)# Update databaseupdate_data {properties: current_props}if self.db.update_device(device_id, update_data):# Update in-memory cacheself.devices[device_id][properties] current_propsself.devices[device_id][last_updated] time.time()return Truereturn Falsedef get_device_history(self, device_id, limit50):Get device historyreturn self.db.get_device_history(device_id, limit)def get_all_locations(self):Get all locationsreturn self.db.get_all_locations()def add_location(self, name, descriptionNone):Add a new locationreturn self.db.add_location(name, description)# Device type implementations class DeviceType:Base class for device typesstaticmethoddef create_device(device_manager, name, location, **kwargs):Create a device of this typeraise NotImplementedError(Subclasses must implement this method)staticmethoddef get_properties_schema():Get JSON schema for device propertiesraise NotImplementedError(Subclasses must implement this method)staticmethoddef validate_command(command, params):Validate a command for this device typeraise NotImplementedError(Subclasses must implement this method)staticmethoddef execute_command(device, command, params):Execute a command on a deviceraise NotImplementedError(Subclasses must implement this method)class LightDevice(DeviceType):Light device type implementationstaticmethoddef create_device(device_manager, name, location, **kwargs):Create a light devicebrightness kwargs.get(brightness, 100)color kwargs.get(color, white)properties {brightness: brightness,color: color,supported_commands: [turn_on, turn_off, set_brightness, set_color]}return device_manager.register_device(name, light, location, properties)staticmethoddef get_properties_schema():Get JSON schema for light propertiesreturn {type: object,properties: {brightness: {type: integer,minimum: 0,maximum: 100,description: Brightness level (0-100)},color: {type: string,description: Light color (name or hex code)}}}staticmethoddef validate_command(command, params):Validate a command for light deviceif command turn_on or command turn_off:return Trueif command set_brightness:if brightness not in params:return Falsebrightness params.get(brightness)return isinstance(brightness, int) and 0 brightness 100if command set_color:return color in paramsreturn Falsestaticmethoddef execute_command(device, command, params):Execute a command on a light devicedevice_id device[id]device_manager DeviceManager()if command turn_on:return device_manager.update_device_status(device_id, on)if command turn_off:return device_manager.update_device_status(device_id, off)if command set_brightness:brightness params.get(brightness, 100)properties {brightness: brightness}return device_manager.update_device_properties(device_id, properties)if command set_color:color params.get(color, white)properties {color: color}return device_manager.update_device_properties(device_id, properties)return Falseclass ThermostatDevice(DeviceType):Thermostat device type implementationstaticmethoddef create_device(device_manager, name, location, **kwargs):Create a thermostat devicecurrent_temp kwargs.get(current_temp, 22)target_temp kwargs.get(target_temp, 22)mode kwargs.get(mode, off) # off, heat, cool, autoproperties {current_temp: current_temp,target_temp: target_temp,mode: mode,supported_commands: [set_temperature, set_mode]}return device_manager.register_device(name, thermostat, location, properties)staticmethoddef get_properties_schema():Get JSON schema for thermostat propertiesreturn {type: object,properties: {current_temp: {type: number,description: Current temperature in Celsius},target_temp: {type: number,minimum: 5,maximum: 35,description: Target temperature in Celsius},mode: {type: string,enum: [off, heat, cool, auto],description: Thermostat mode}}}staticmethoddef validate_command(command, params):Validate a command for thermostat deviceif command set_temperature:if temperature not in params:return Falsetemp params.get(temperature)return isinstance(temp, (int, float)) and 5 temp 35if command set_mode:if mode not in params:return Falsemode params.get(mode)return mode in [off, heat, cool, auto]return Falsestaticmethoddef execute_command(device, command, params):Execute a command on a thermostat devicedevice_id device[id]device_manager DeviceManager()if command set_temperature:temperature params.get(temperature)properties {target_temp: temperature}# If device is off, turn it on in heat or cool modeif device[properties].get(mode) off:properties[mode] autoreturn device_manager.update_device_properties(device_id, properties)if command set_mode:mode params.get(mode)properties {mode: mode}# Update status based on modestatus on if mode ! off else offdevice_manager.update_device_status(device_id, status)return device_manager.update_device_properties(device_id, properties)return False# Factory for creating devices of different types class DeviceFactory:Factory class for creating devices of different types_device_types {light: LightDevice,thermostat: ThermostatDevice}classmethoddef register_device_type(cls, type_name, device_class):Register a new device typecls._device_types[type_name] device_classclassmethoddef create_device(cls, device_manager, type_name, name, location, **kwargs):Create a device of the specified typeif type_name not in cls._device_types:raise ValueError(fUnknown device type: {type_name})device_class cls._device_types[type_name]return device_class.create_device(device_manager, name, location, **kwargs)classmethoddef get_device_types(cls):Get all registered device typesreturn list(cls._device_types.keys())classmethoddef get_properties_schema(cls, type_name):Get properties schema for a device typeif type_name not in cls._device_types:raise ValueError(fUnknown device type: {type_name})device_class cls._device_types[type_name]return device_class.get_properties_schema()classmethoddef execute_command(cls, device, command, params):Execute a command on a devicedevice_type device[type]if device_type not in cls._device_types:raise ValueError(fUnknown device type: {device_type})device_class cls._device_types[device_type]# Validate commandif not device_class.validate_command(command, params):return False# Execute commandreturn device_class.execute_command(device, command, params)app\scene_manager.py Scene Manager for Smart Home System Handles scene operations and executionimport uuid from .device_manager import DeviceManagerclass SceneManager:def __init__(self, dbNone, device_managerNone):Initialize Scene Managerfrom .database import Databaseself.db db if db else Database()self.device_manager device_manager if device_manager else DeviceManager(self.db)def create_scene(self, name, descriptionNone, iconNone, actionsNone):Create a new sceneif not name:raise ValueError(Scene name is required)scene_data {name: name,description: description,icon: icon or lightbulb,actions: actions or []}scene_id self.db.add_scene(scene_data)if scene_id:return self.get_scene(scene_id)return Nonedef update_scene(self, scene_id, update_data):Update an existing sceneif not scene_id:return False# Validate scene existsscene self.get_scene(scene_id)if not scene:return False# Update sceneif self.db.update_scene(scene_id, update_data):return self.get_scene(scene_id)return Nonedef delete_scene(self, scene_id):Delete a scenereturn self.db.delete_scene(scene_id)def get_scene(self, scene_id):Get a scene by IDreturn self.db.get_scene(scene_id)def get_all_scenes(self):Get all scenesreturn self.db.get_all_scenes()def activate_scene(self, scene_id):Activate a scene by executing all its actionsscene self.get_scene(scene_id)if not scene:return Falseresults []for action in scene[actions]:device_id action[device_id]action_type action[action_type]action_params action[action_params]# Get devicedevice self.device_manager.get_device(device_id)if not device:results.append({device_id: device_id,success: False,message: Device not found})continue# Execute actiontry:if action_type set_status:status action_params.get(status)if status:self.device_manager.update_device_status(device_id, status)results.append({device_id: device_id,success: True,action: set_status,value: status})elif action_type set_property:property_name action_params.get(property)property_value action_params.get(value)if property_name and property_value is not None:properties {property_name: property_value}self.device_manager.update_device_properties(device_id, properties)results.append({device_id: device_id,success: True,action: set_property,property: property_name,value: property_value})elif action_type execute_command:command action_params.get(command)params action_params.get(params, {})if command:# This would call the device-specific command execution# For now, well just update the device propertiesself.device_manager.update_device_properties(device_id, params)results.append({device_id: device_id,success: True,action: execute_command,command: command,params: params})else:results.append({device_id: device_id,success: False,message: fUnsupported action type: {action_type}})except Exception as e:results.append({device_id: device_id,success: False,message: str(e)})return {scene_id: scene_id,scene_name: scene[name],success: any(result[success] for result in results),results: results}def add_device_to_scene(self, scene_id, device_id, action_type, action_params):Add a device action to a scenescene self.get_scene(scene_id)if not scene:return False# Validate device existsdevice self.device_manager.get_device(device_id)if not device:return False# Create actionaction {device_id: device_id,action_type: action_type,action_params: action_params}# Add action to sceneaction_id self.db.add_scene_action(scene_id, action)return action_id is not Nonedef remove_device_from_scene(self, scene_id, action_id):Remove a device action from a scene# This would require adding a method to delete a specific action# For now, well update the scene with all actions except the one to removescene self.get_scene(scene_id)if not scene:return False# Filter out the action to removeupdated_actions [action for action in scene[actions] if action[id] ! action_id]# Update scene with new actionsreturn self.db.update_scene(scene_id, {actions: updated_actions})app_init_.py Smart Home System Applicationfrom flask import Flask from flask_cors import CORSdef create_app():Create and configure the Flask applicationapp Flask(__name__, static_folder../static,template_folder../templates)# Enable CORSCORS(app)# Load configurationapp.config.from_mapping(SECRET_KEYdev,DATABASENone,)# Register blueprintsfrom .routes import apiapp.register_blueprint(api.bp)return appapp\routes\api.py API routes for Smart Home Systemfrom flask import Blueprint, request, jsonify, current_app from ..device_manager import DeviceManager, DeviceFactory from ..scene_manager import SceneManagerbp Blueprint(api, __name__, url_prefix/api)# Initialize device manager device_manager DeviceManager() # Initialize scene manager scene_manager SceneManager(device_managerdevice_manager)bp.route(/devices, methods[GET]) def get_devices():Get all devices or filter by type/locationdevice_type request.args.get(type)location request.args.get(location)if device_type:devices device_manager.get_devices_by_type(device_type)elif location:devices device_manager.get_devices_by_location(location)else:devices device_manager.get_all_devices()return jsonify(devices)bp.route(/devices/device_id, methods[GET]) def get_device(device_id):Get a device by IDdevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404return jsonify(device)bp.route(/devices, methods[POST]) def create_device():Create a new devicedata request.jsonif not data:return jsonify({error: No data provided}), 400# Required fieldsname data.get(name)device_type data.get(type)location data.get(location)if not name or not device_type:return jsonify({error: Name and type are required}), 400# Check if device type is supportedif device_type not in DeviceFactory.get_device_types():return jsonify({error: fUnsupported device type: {device_type}}), 400# Create devicetry:device_id DeviceFactory.create_device(device_manager, device_type, name, location, **data.get(properties, {}))if not device_id:return jsonify({error: Failed to create device}), 500# Get the created devicedevice device_manager.get_device(device_id)return jsonify(device), 201except Exception as e:return jsonify({error: str(e)}), 500bp.route(/devices/device_id, methods[PUT]) def update_device(device_id):Update a devicedevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404data request.jsonif not data:return jsonify({error: No data provided}), 400# Update nameif name in data:device[name] data[name]# Update locationif location in data:device[location] data[location]# Update propertiesif properties in data and isinstance(data[properties], dict):device_manager.update_device_properties(device_id, data[properties])# Update in databasedevice_manager.db.update_device(device_id, {name: device[name],location: device[location]})return jsonify(device_manager.get_device(device_id))bp.route(/devices/device_id, methods[DELETE]) def delete_device(device_id):Delete a devicedevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404if device_manager.delete_device(device_id):return jsonify({message: Device deleted successfully})return jsonify({error: Failed to delete device}), 500bp.route(/devices/device_id/control, methods[POST]) def control_device(device_id):Control a devicedevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404data request.jsonif not data:return jsonify({error: No data provided}), 400command data.get(command)params data.get(params, {})if not command:return jsonify({error: Command is required}), 400# Check if command is supported by devicesupported_commands device.get(properties, {}).get(supported_commands, [])if command not in supported_commands:return jsonify({error: fUnsupported command: {command}}), 400# Execute commandtry:result DeviceFactory.execute_command(device, command, params)if result:# Get updated deviceupdated_device device_manager.get_device(device_id)return jsonify({message: Command executed successfully,device: updated_device})return jsonify({error: Failed to execute command}), 500except Exception as e:return jsonify({error: str(e)}), 500bp.route(/devices/device_id/history, methods[GET]) def get_device_history(device_id):Get device historydevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404limit request.args.get(limit, 50, typeint)history device_manager.get_device_history(device_id, limit)return jsonify(history)bp.route(/device-types, methods[GET]) def get_device_types():Get all supported device typesdevice_types DeviceFactory.get_device_types()# Get schema for each device typeresult {}for device_type in device_types:try:schema DeviceFactory.get_properties_schema(device_type)result[device_type] {name: device_type,schema: schema}except Exception:result[device_type] {name: device_type,schema: {}}return jsonify(result)bp.route(/locations, methods[GET]) def get_locations():Get all locationslocations device_manager.db.get_all_locations()return jsonify(locations)bp.route(/locations, methods[POST]) def add_location():Add a new locationdata request.jsonif not data:return jsonify({error: No data provided}), 400name data.get(name)description data.get(description)if not name:return jsonify({error: Name is required}), 400location_id device_manager.db.add_location(name, description)if location_id:return jsonify({id: location_id,name: name,description: description}), 201return jsonify({error: Failed to add location}), 500# Scene routes bp.route(/scenes, methods[GET]) def get_scenes():Get all scenesscenes scene_manager.get_all_scenes()return jsonify(scenes)bp.route(/scenes/scene_id, methods[GET]) def get_scene(scene_id):Get a scene by IDscene scene_manager.get_scene(scene_id)if not scene:return jsonify({error: Scene not found}), 404return jsonify(scene)bp.route(/scenes, methods[POST]) def create_scene():Create a new scenedata request.jsonif not data:return jsonify({error: No data provided}), 400name data.get(name)description data.get(description)icon data.get(icon)actions data.get(actions, [])if not name:return jsonify({error: Name is required}), 400try:scene scene_manager.create_scene(name, description, icon, actions)if scene:return jsonify(scene), 201return jsonify({error: Failed to create scene}), 500except Exception as e:return jsonify({error: str(e)}), 500bp.route(/scenes/scene_id, methods[PUT]) def update_scene(scene_id):Update a scenescene scene_manager.get_scene(scene_id)if not scene:return jsonify({error: Scene not found}), 404data request.jsonif not data:return jsonify({error: No data provided}), 400try:updated_scene scene_manager.update_scene(scene_id, data)if updated_scene:return jsonify(updated_scene)return jsonify({error: Failed to update scene}), 500except Exception as e:return jsonify({error: str(e)}), 500bp.route(/scenes/scene_id, methods[DELETE]) def delete_scene(scene_id):Delete a scenescene scene_manager.get_scene(scene_id)if not scene:return jsonify({error: Scene not found}), 404if scene_manager.delete_scene(scene_id):return jsonify({message: Scene deleted successfully})return jsonify({error: Failed to delete scene}), 500bp.route(/scenes/scene_id/activate, methods[POST]) def activate_scene(scene_id):Activate a scenescene scene_manager.get_scene(scene_id)if not scene:return jsonify({error: Scene not found}), 404result scene_manager.activate_scene(scene_id)if result and result.get(success):return jsonify(result)return jsonify({error: Failed to activate scene, details: result}), 500bp.route(/scenes/scene_id/devices, methods[POST]) def add_device_to_scene(scene_id):Add a device to a scenescene scene_manager.get_scene(scene_id)if not scene:return jsonify({error: Scene not found}), 404data request.jsonif not data:return jsonify({error: No data provided}), 400device_id data.get(device_id)action_type data.get(action_type)action_params data.get(action_params, {})if not device_id or not action_type:return jsonify({error: Device ID and action type are required}), 400# Check if device existsdevice device_manager.get_device(device_id)if not device:return jsonify({error: Device not found}), 404if scene_manager.add_device_to_scene(scene_id, device_id, action_type, action_params):return jsonify({message: Device added to scene successfully})return jsonify({error: Failed to add device to scene}), 500app\routes_init_.py static\css\styles.css /* Smart Home System CSS *//* General Styles */ body {font-family: Microsoft YaHei, Segoe UI, Tahoma, Geneva, Verdana, sans-serif;background-color: #f8f9fa; }.card {box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);transition: all 0.3s ease; }.card:hover {box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);transform: translateY(-2px); }/* Device Card Styles */ .card.border-success {border-width: 2px; }.card.border-danger {border-width: 2px; }/* Color Button Styles */ .color-btn {width: 30px;height: 30px;border-radius: 50%;border: 1px solid #dee2e6; }.color-btn:hover {transform: scale(1.1); }/* Status Badge Styles */ .badge.bg-success {background-color: #28a745 !important; }.badge.bg-danger {background-color: #dc3545 !important; }.badge.bg-secondary {background-color: #6c757d !important; }/* Progress Bar Animation */ .progress-bar {transition: width 1s ease;animation: progress-bar-stripes 1s linear infinite; }keyframes progress-bar-stripes {0% {background-position: 1rem 0;}100% {background-position: 0 0;} }/* Custom Scrollbar */ ::-webkit-scrollbar {width: 8px; }::-webkit-scrollbar-track {background: #f1f1f1; }::-webkit-scrollbar-thumb {background: #888;border-radius: 4px; }::-webkit-scrollbar-thumb:hover {background: #555; }/* Modal Animation */ .modal.fade .modal-dialog {transition: transform 0.3s ease-out;transform: translateY(-50px); }.modal.show .modal-dialog {transform: none; }/* Toast Notification */ .toast {opacity: 1 !important; }/* Responsive Adjustments */ media (max-width: 768px) {.card-footer {flex-direction: column;gap: 10px;align-items: center;}.btn-group {width: 100%;} } 3. JavaScript Applicationstatic\js\app.js /*** Smart Home System - Frontend Application*/// API Base URL const API_BASE_URL /api;// Bootstrap components let toastElement; let addDeviceModal; let editDeviceModal; let deviceHistoryModal; let addLocationModal; let editLocationModal;// Create Vue application const app Vue.createApp({data() {return {// UI stateactiveTab: devices,// Datadevices: [],locations: [],deviceTypes: [],deviceHistory: [],// FiltersdeviceTypeFilter: ,locationFilter: ,statusFilter: ,// Selected itemsselectedDevice: null,editingDevice: null,editingLocation: null,// Form datanewDevice: {name: ,type: light,location: ,properties: {brightness: 100,color: white,current_temp: 22,target_temp: 22,mode: off}},newLocation: {name: ,description: }};},computed: {filteredDevices() {return this.devices.filter(device {let matchesType true;let matchesLocation true;let matchesStatus true;if (this.deviceTypeFilter) {matchesType device.type this.deviceTypeFilter;}if (this.locationFilter) {matchesLocation device.location this.locationFilter;}if (this.statusFilter) {matchesStatus device.status this.statusFilter;}return matchesType matchesLocation matchesStatus;});}},methods: {// Device operationsasync loadDevices() {try {const response await axios.get(${API_BASE_URL}/devices);this.devices response.data;} catch (error) {this.showToast(加载设备失败, error);console.error(Error loading devices:, error);}},async loadDeviceTypes() {try {const response await axios.get(${API_BASE_URL}/device-types);this.deviceTypes Object.keys(response.data);} catch (error) {this.showToast(加载设备类型失败, error);console.error(Error loading device types:, error);}},async addDevice() {try {// Prepare properties based on device typelet properties {};if (this.newDevice.type light) {properties {brightness: parseInt(this.newDevice.properties.brightness),color: this.newDevice.properties.color};} else if (this.newDevice.type thermostat) {properties {current_temp: parseFloat(this.newDevice.properties.current_temp),target_temp: parseFloat(this.newDevice.properties.target_temp),mode: this.newDevice.properties.mode};}const response await axios.post(${API_BASE_URL}/devices, {name: this.newDevice.name,type: this.newDevice.type,location: this.newDevice.location,properties: properties});// Add new device to listthis.devices.push(response.data);// Reset formthis.resetNewDeviceForm();// Close modaladdDeviceModal.hide();this.showToast(设备添加成功);} catch (error) {this.showToast(添加设备失败, error);console.error(Error adding device:, error);}},async updateDevice() {if (!this.editingDevice) return;try {const deviceId this.editingDevice.id;await axios.put(${API_BASE_URL}/devices/${deviceId}, {name: this.editingDevice.name,location: this.editingDevice.location});// Update device in listconst index this.devices.findIndex(d d.id deviceId);if (index ! -1) {this.devices[index].name this.editingDevice.name;this.devices[index].location this.editingDevice.location;}// Close modaleditDeviceModal.hide();this.showToast(设备更新成功);} catch (error) {this.showToast(更新设备失败, error);console.error(Error updating device:, error);}},async deleteDevice(device) {if (!confirm(确定要删除设备 ${device.name} 吗)) return;try {await axios.delete(${API_BASE_URL}/devices/${device.id});// Remove device from listthis.devices this.devices.filter(d d.id ! device.id);this.showToast(设备删除成功);} catch (error) {this.showToast(删除设备失败, error);console.error(Error deleting device:, error);}},async toggleDevice(device) {const command device.status on ? turn_off : turn_on;try {const response await axios.post(${API_BASE_URL}/devices/${device.id}/control, {command: command});// Update device in listconst index this.devices.findIndex(d d.id device.id);if (index ! -1) {this.devices[index] response.data.device;}this.showToast(设备${command turn_on ? 开启 : 关闭}成功);} catch (error) {this.showToast(设备${command turn_on ? 开启 : 关闭}失败, error);console.error(Error controlling device:, error);}},async setBrightness(deviceId, brightness) {try {const response await axios.post(${API_BASE_URL}/devices/${deviceId}/control, {command: set_brightness,params: {brightness: parseInt(brightness)}});// Update device in listconst index this.devices.findIndex(d d.id deviceId);if (index ! -1) {this.devices[index] response.data.device;}} catch (error) {this.showToast(设置亮度失败, error);console.error(Error setting brightness:, error);}},async setColor(deviceId, color) {try {const response await axios.post(${API_BASE_URL}/devices/${deviceId}/control, {command: set_color,params: {color: color}});// Update device in listconst index this.devices.findIndex(d d.id deviceId);if (index ! -1) {this.devices[index] response.data.device;}} catch (error) {this.showToast(设置颜色失败, error);console.error(Error setting color:, error);}},async adjustTemperature(deviceId, delta) {const device this.devices.find(d d.id deviceId);if (!device) return;const currentTemp device.properties.target_temp;const newTemp Math.min(Math.max(currentTemp delta, 5), 35);try {const response await axios.post(${API_BASE_URL}/devices/${deviceId}/control, {command: set_temperature,params: {temperature: newTemp}});// Update device in listconst index this.devices.findIndex(d d.id deviceId);if (index ! -1) {this.devices[index] response.data.device;}} catch (error) {this.showToast(设置温度失败, error);console.error(Error setting temperature:, error);}},async setThermostatMode(deviceId, mode) {try {const response await axios.post(${API_BASE_URL}/devices/${deviceId}/control, {command: set_mode,params: {mode: mode}});// Update device in listconst index this.devices.findIndex(d d.id deviceId);if (index ! -1) {this.devices[index] response.data.device;}} catch (error) {this.showToast(设置模式失败, error);console.error(Error setting mode:, error);}},async loadDeviceHistory(deviceId) {try {const response await axios.get(${API_BASE_URL}/devices/${deviceId}/history);this.deviceHistory response.data;} catch (error) {this.showToast(加载设备历史记录失败, error);console.error(Error loading device history:, error);}},// Location operationsasync loadLocations() {try {const response await axios.get(${API_BASE_URL}/locations);this.locations response.data;} catch (error) {this.showToast(加载位置失败, error);console.error(Error loading locations:, error);}},async addLocation() {try {await axios.post(${API_BASE_URL}/locations, {name: this.newLocation.name,description: this.newLocation.description});// Reload locationsawait this.loadLocations();// Reset formthis.newLocation {name: ,description: };// Close modaladdLocationModal.hide();this.showToast(位置添加成功);} catch (error) {this.showToast(添加位置失败, error);console.error(Error adding location:, error);}},// UI operationsshowAddDeviceModal() {this.resetNewDeviceForm();addDeviceModal.show();},showEditDeviceModal(device) {this.editingDevice { ...device };editDeviceModal.show();},showDeviceHistory(device) {this.selectedDevice device;this.deviceHistory [];deviceHistoryModal.show();this.loadDeviceHistory(device.id);},showAddLocationModal() {this.newLocation {name: ,description: };addLocationModal.show();},showEditLocationModal(location) {this.editingLocation { ...location };editLocationModal.show();},resetNewDeviceForm() {this.newDevice {name: ,type: light,location: ,properties: {brightness: 100,color: white,current_temp: 22,target_temp: 22,mode: off}};},filterDevices() {// This method is called when filters change// The actual filtering is done in the computed property},getDeviceCountByType(type) {return this.devices.filter(device device.type type).length;},getDeviceCountByLocation(location) {return this.devices.filter(device device.location location).length;},getStatusBadgeClass(status) {if (status on) return bg-success;if (status off) return bg-secondary;return bg-danger;},getStatusText(status) {if (status on) return 开启;if (status off) return 关闭;return 离线;},formatDate(dateString) {if (!dateString) return ;const date new Date(dateString);return date.toLocaleString(zh-CN, {year: numeric,month: 2-digit,day: 2-digit,hour: 2-digit,minute: 2-digit,second: 2-digit});},showToast(message, type success) {const toastEl document.getElementById(toast);const toastMessageEl document.getElementById(toastMessage);toastMessageEl.textContent message;toastEl.classList.remove(bg-success, bg-danger);toastEl.classList.add(type success ? bg-success : bg-danger);const toast new bootstrap.Toast(toastEl);toast.show();}},mounted() {// Initialize Bootstrap componentstoastElement document.getElementById(toast);addDeviceModal new bootstrap.Modal(document.getElementById(addDeviceModal));editDeviceModal new bootstrap.Modal(document.getElementById(editDeviceModal));deviceHistoryModal new bootstrap.Modal(document.getElementById(deviceHistoryModal));addLocationModal new bootstrap.Modal(document.getElementById(addLocationModal));editLocationModal new bootstrap.Modal(document.getElementById(editLocationModal));// Load datathis.loadDevices();this.loadDeviceTypes();this.loadLocations();} });// Mount Vue application app.mount(#app); 4. Requirements Filetemplates\index.html !DOCTYPE html html langzh-CN headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0title智能家居控制系统 - 设备管理/titlelink relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.2.3/dist/css/bootstrap.min.csslink relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap-icons1.10.0/font/bootstrap-icons.csslink relstylesheet href/static/css/styles.css /head bodydiv idappnav classnavbar navbar-expand-lg navbar-dark bg-primarydiv classcontainer-fluida classnavbar-brand href#i classbi bi-house-gear-fill me-2/i智能家居控制系统/abutton classnavbar-toggler typebutton data-bs-togglecollapse data-bs-target#navbarNavspan classnavbar-toggler-icon/span/buttondiv classcollapse navbar-collapse idnavbarNavul classnavbar-navli classnav-itema classnav-link active href# clickactiveTab devicesi classbi bi-grid-3x3-gap-fill me-1/i设备管理/a/lili classnav-itema classnav-link href# clickactiveTab locationsi classbi bi-geo-alt-fill me-1/i位置管理/a/lili classnav-itema classnav-link href# clickactiveTab statisticsi classbi bi-bar-chart-fill me-1/i数据统计/a/li/ul/div/div/navdiv classcontainer mt-4!-- Devices Tab --div v-ifactiveTab devicesdiv classd-flex justify-content-between align-items-center mb-4h2设备管理/h2button classbtn btn-primary clickshowAddDeviceModali classbi bi-plus-lg me-1/i添加设备/button/div!-- Filters --div classrow mb-4div classcol-md-4div classinput-groupspan classinput-group-text类型/spanselect classform-select v-modeldeviceTypeFilter changefilterDevicesoption value全部/optionoption v-fortype in deviceTypes :valuetype{{ type }}/option/select/div/divdiv classcol-md-4div classinput-groupspan classinput-group-text位置/spanselect classform-select v-modellocationFilter changefilterDevicesoption value全部/optionoption v-forlocation in locations :valuelocation.name{{ location.name }}/option/select/div/divdiv classcol-md-4div classinput-groupspan classinput-group-text状态/spanselect classform-select v-modelstatusFilter changefilterDevicesoption value全部/optionoption valueon开启/optionoption valueoff关闭/optionoption valueoffline离线/option/select/div/div/div!-- Devices List --div classrow v-iffilteredDevices.length 0div classcol-md-4 mb-4 v-fordevice in filteredDevices :keydevice.iddiv classcard h-100 :class{border-success: device.status on, border-danger: device.status offline}div classcard-header d-flex justify-content-between align-items-centerh5 classcard-title mb-0{{ device.name }}/h5span classbadge :classgetStatusBadgeClass(device.status){{ getStatusText(device.status) }}/span/divdiv classcard-bodyp classcard-texti classbi bi-tag-fill me-2/i类型: {{ device.type }}/pp classcard-texti classbi bi-geo-alt-fill me-2/i位置: {{ device.location || 未设置 }}/p!-- Light Device Controls --div v-ifdevice.type light device.status ! offlinediv classmb-3label classform-label亮度: {{ device.properties.brightness }}%/labelinput typerange classform-range min0 max100 step1:valuedevice.properties.brightnesschangesetBrightness(device.id, $event.target.value)/divdiv classmb-3label classform-label颜色:/labeldiv classd-flexbutton classbtn btn-sm color-btn me-1 v-forcolor in [white, red, green, blue, yellow]:style{backgroundColor: color}clicksetColor(device.id, color)/button/div/div/div!-- Thermostat Device Controls --div v-ifdevice.type thermostat device.status ! offlinediv classmb-3label classform-label当前温度: {{ device.properties.current_temp }}°C/label/divdiv classmb-3label classform-label目标温度: {{ device.properties.target_temp }}°C/labeldiv classd-flex align-items-centerbutton classbtn btn-sm btn-outline-primary me-2 clickadjustTemperature(device.id, -1)i classbi bi-dash/i/buttonspan classfs-5{{ device.properties.target_temp }}°C/spanbutton classbtn btn-sm btn-outline-primary ms-2 clickadjustTemperature(device.id, 1)i classbi bi-plus/i/button/div/divdiv classmb-3label classform-label模式:/labeldiv classbtn-group w-100button classbtn btn-sm :classdevice.properties.mode off ? btn-primary : btn-outline-primaryclicksetThermostatMode(device.id, off)关闭/buttonbutton classbtn btn-sm :classdevice.properties.mode heat ? btn-primary : btn-outline-primaryclicksetThermostatMode(device.id, heat)制热/buttonbutton classbtn btn-sm :classdevice.properties.mode cool ? btn-primary : btn-outline-primaryclicksetThermostatMode(device.id, cool)制冷/buttonbutton classbtn btn-sm :classdevice.properties.mode auto ? btn-primary : btn-outline-primaryclicksetThermostatMode(device.id, auto)自动/button/div/div/div/divdiv classcard-footer d-flex justify-content-betweenbutton classbtn btn-sm :classdevice.status on ? btn-danger : btn-successclicktoggleDevice(device):disableddevice.status offline{{ device.status on ? 关闭 : 开启 }}/buttondivbutton classbtn btn-sm btn-info me-1 clickshowDeviceHistory(device)i classbi bi-clock-history/i/buttonbutton classbtn btn-sm btn-primary me-1 clickshowEditDeviceModal(device)i classbi bi-pencil/i/buttonbutton classbtn btn-sm btn-danger clickdeleteDevice(device)i classbi bi-trash/i/button/div/div/div/div/divdiv classalert alert-info v-else没有找到符合条件的设备。/div/div!-- Locations Tab --div v-ifactiveTab locationsdiv classd-flex justify-content-between align-items-center mb-4h2位置管理/h2button classbtn btn-primary clickshowAddLocationModali classbi bi-plus-lg me-1/i添加位置/button/divdiv classrowdiv classcol-md-4 mb-4 v-forlocation in locations :keylocation.iddiv classcard h-100div classcard-headerh5 classcard-title mb-0{{ location.name }}/h5/divdiv classcard-bodyp classcard-text v-iflocation.description{{ location.description }}/pp classcard-text v-else无描述/pdiv classmt-3h6设备数量:/h6p{{ getDeviceCountByLocation(location.name) }} 个设备/p/div/divdiv classcard-footer d-flex justify-content-endbutton classbtn btn-sm btn-primary me-1 clickshowEditLocationModal(location)i classbi bi-pencil/i/buttonbutton classbtn btn-sm btn-danger clickdeleteLocation(location):disabledgetDeviceCountByLocation(location.name) 0i classbi bi-trash/i/button/div/div/div/div/div!-- Statistics Tab --div v-ifactiveTab statisticsh2 classmb-4数据统计/h2div classrowdiv classcol-md-4 mb-4div classcard h-100div classcard-header bg-primary text-whiteh5 classcard-title mb-0设备总览/h5/divdiv classcard-bodydiv classd-flex justify-content-between mb-3span总设备数:/spanspan classfw-bold{{ devices.length }}/span/divdiv classd-flex justify-content-between mb-3span在线设备:/spanspan classfw-bold{{ devices.filter(d d.status ! offline).length }}/span/divdiv classd-flex justify-content-between mb-3span开启设备:/spanspan classfw-bold{{ devices.filter(d d.status on).length }}/span/divdiv classd-flex justify-content-betweenspan离线设备:/spanspan classfw-bold{{ devices.filter(d d.status offline).length }}/span/div/div/div/divdiv classcol-md-4 mb-4div classcard h-100div classcard-header bg-success text-whiteh5 classcard-title mb-0设备类型分布/h5/divdiv classcard-bodydiv v-fortype in deviceTypes :keytype classmb-3div classd-flex justify-content-between mb-1span{{ type }}:/spanspan classfw-bold{{ getDeviceCountByType(type) }}/span/divdiv classprogressdiv classprogress-bar roleprogressbar:style{width: (getDeviceCountByType(type) / devices.length * 100) %}:aria-valuenowgetDeviceCountByType(type)aria-valuemin0 :aria-valuemaxdevices.length/div/div/div/div/div/divdiv classcol-md-4 mb-4div classcard h-100div classcard-header bg-info text-whiteh5 classcard-title mb-0位置分布/h5/divdiv classcard-bodydiv v-forlocation in locations :keylocation.id classmb-3div classd-flex justify-content-between mb-1span{{ location.name }}:/spanspan classfw-bold{{ getDeviceCountByLocation(location.name) }}/span/divdiv classprogressdiv classprogress-bar bg-info roleprogressbar:style{width: (getDeviceCountByLocation(location.name) / devices.length * 100) %}:aria-valuenowgetDeviceCountByLocation(location.name)aria-valuemin0 :aria-valuemaxdevices.length/div/div/div/div/div/div/div/div/div!-- Add Device Modal --div classmodal fade idaddDeviceModal tabindex-1 aria-hiddentruediv classmodal-dialogdiv classmodal-contentdiv classmodal-headerh5 classmodal-title添加设备/h5button typebutton classbtn-close data-bs-dismissmodal aria-labelClose/button/divdiv classmodal-bodyform submit.preventaddDevicediv classmb-3label classform-label设备名称/labelinput typetext classform-control v-modelnewDevice.name required/divdiv classmb-3label classform-label设备类型/labelselect classform-select v-modelnewDevice.type requiredoption v-fortype in deviceTypes :valuetype{{ type }}/option/select/divdiv classmb-3label classform-label位置/labelselect classform-select v-modelnewDevice.locationoption value未设置/optionoption v-forlocation in locations :valuelocation.name{{ location.name }}/option/select/div!-- Light device properties --div v-ifnewDevice.type lightdiv classmb-3label classform-label亮度/labelinput typerange classform-range min0 max100 step1 v-modelnewDevice.properties.brightnessdiv classtext-center{{ newDevice.properties.brightness }}%/div/divdiv classmb-3label classform-label颜色/labelselect classform-select v-modelnewDevice.properties.coloroption valuewhite白色/optionoption valuered红色/optionoption valuegreen绿色/optionoption valueblue蓝色/optionoption valueyellow黄色/option/select/div/div!-- Thermostat device properties --div v-ifnewDevice.type thermostatdiv classmb-3label classform-label当前温度 (°C)/labelinput typenumber classform-control v-modelnewDevice.properties.current_temp min0 max40/divdiv classmb-3label classform-label目标温度 (°C)/labelinput typenumber classform-control v-modelnewDevice.properties.target_temp min5 max35/divdiv classmb-3label classform-label模式/labelselect classform-select v-modelnewDevice.properties.modeoption valueoff关闭/optionoption valueheat制热/optionoption valuecool制冷/optionoption valueauto自动/option/select/div/divdiv classtext-endbutton typebutton classbtn btn-secondary me-2 data-bs-dismissmodal取消/buttonbutton typesubmit classbtn btn-primary添加/button/div/form/div/div/div/div!-- Edit Device Modal --div classmodal fade ideditDeviceModal tabindex-1 aria-hiddentruediv classmodal-dialogdiv classmodal-contentdiv classmodal-headerh5 classmodal-title编辑设备/h5button typebutton classbtn-close data-bs-dismissmodal aria-labelClose/button/divdiv classmodal-bodyform submit.preventupdateDevice v-ifeditingDevicediv classmb-3label classform-label设备名称/labelinput typetext classform-control v-modeleditingDevice.name required/divdiv classmb-3label classform-label位置/labelselect classform-select v-modeleditingDevice.locationoption value未设置/optionoption v-forlocation in locations :valuelocation.name{{ location.name }}/option/select/divdiv classtext-endbutton typebutton classbtn btn-secondary me-2 data-bs-dismissmodal取消/buttonbutton typesubmit classbtn btn-primary保存/button/div/form/div/div/div/div!-- Device History Modal --div classmodal fade iddeviceHistoryModal tabindex-1 aria-hiddentruediv classmodal-dialog modal-lgdiv classmodal-contentdiv classmodal-headerh5 classmodal-title设备历史记录/h5button typebutton classbtn-close data-bs-dismissmodal aria-labelClose/button/divdiv classmodal-bodyh6 v-ifselectedDevice{{ selectedDevice.name }}/h6div classtable-responsivetable classtable table-stripedtheadtrth时间/thth状态/thth属性/th/tr/theadtbodytr v-forentry in deviceHistory :keyentry.idtd{{ formatDate(entry.timestamp) }}/tdtdspan classbadge :classgetStatusBadgeClass(entry.status){{ getStatusText(entry.status) }}/span/tdtdpre v-ifentry.properties classmb-0{{ JSON.stringify(entry.properties, null, 2) }}/prespan v-else-/span/td/tr/tbody/table/divdiv classalert alert-info v-ifdeviceHistory.length 0没有历史记录。/div/div/div/div/div!-- Add Location Modal --div classmodal fade idaddLocationModal tabindex-1 aria-hiddentruediv classmodal-dialogdiv classmodal-contentdiv classmodal-headerh5 classmodal-title添加位置/h5button typebutton classbtn-close data-bs-dismissmodal aria-labelClose/button/divdiv classmodal-bodyform submit.preventaddLocationdiv classmb-3label classform-label位置名称/labelinput typetext classform-control v-modelnewLocation.name required/divdiv classmb-3label classform-label描述/labeltextarea classform-control v-modelnewLocation.description rows3/textarea/divdiv classtext-endbutton typebutton classbtn btn-secondary me-2 data-bs-dismissmodal取消/buttonbutton typesubmit classbtn btn-primary添加/button/div/form/div/div/div/div!-- Edit Location Modal --div classmodal fade ideditLocationModal tabindex-1 aria-hiddentruediv classmodal-dialogdiv classmodal-contentdiv classmodal-headerh5 classmodal-title编辑位置/h5button typebutton classbtn-close data-bs-dismissmodal aria-labelClose/button/divdiv classmodal-bodyform submit.preventupdateLocation v-ifeditingLocationdiv classmb-3label classform-label位置名称/labelinput typetext classform-control v-modeleditingLocation.name required/divdiv classmb-3label classform-label描述/labeltextarea classform-control v-modeleditingLocation.description rows3/textarea/divdiv classtext-endbutton typebutton classbtn btn-secondary me-2 data-bs-dismissmodal取消/buttonbutton typesubmit classbtn btn-primary保存/button/div/form/div/div/div/div!-- Toast Notifications --div classtoast-container position-fixed bottom-0 end-0 p-3div idtoast classtoast rolealert aria-liveassertive aria-atomictruediv classtoast-headerstrong classme-auto通知/strongbutton typebutton classbtn-close data-bs-dismisstoast aria-labelClose/button/divdiv classtoast-body idtoastMessage/div/div/div/divscript srchttps://cdn.jsdelivr.net/npm/bootstrap5.2.3/dist/js/bootstrap.bundle.min.js/scriptscript srchttps://cdn.jsdelivr.net/npm/vue3.2.45/dist/vue.global.js/scriptscript srchttps://cdn.jsdelivr.net/npm/axios/dist/axios.min.js/scriptscript src/static/js/app.js/script /body /html
http://www.w-s-a.com/news/631973/

相关文章:

  • 景区旅游网站平台建设公司企业网站源码
  • 免费高清网站推荐喂来苏州网络科技有限公司
  • php做的大型网站有哪些备案博客域名做视频网站会怎么样
  • 去哪网站备案吗昭通网站建设
  • flash企业网站源码建筑材料采购网站
  • 网站可以换虚拟主机吗部门做网站优点
  • 如何做分类网站信息营销莱芜网页定制
  • 班级网站建设感想中国做视频网站有哪些
  • 做刷票的网站wordpress图片链接插件
  • 给客户做网站图片侵权沈阳做网站的地方
  • 网站开发步骤规划蓝天云免费空间主机
  • 网站字体规范wordpress找不到页面内容编辑
  • 静态网站建设参考文献茂名营销型网站制作公司
  • 君山区建设局网站风铃微网站怎么做
  • 购物网站销售管理合肥网络推广平台
  • 网站建设规划书txt微盘注册帐号
  • 小说网站开发实训报告企业网盘收费标准
  • mvc网站开发医疗医院网站建设
  • 天津市建设厅官方网站wordpress设置404
  • 贵阳好的网站建设免费正能量网站下载ww
  • 免费学习的网站平台自建站seo如何做
  • 海南三亚做网站公众号版面设计创意
  • 学校网站建设目的与意义合肥网页定制
  • 网站查询地址网站建设与维护费用
  • 做网站哪些软件比较好合肥外贸网站建设公司
  • 建网站需要哪些条件专业网站设计报价
  • 定制网站开发技术化妆品的网站布局设计图片大全
  • 网站模糊设计发布产品的免费平台有哪些
  • 网站建站什么目录桂林网站建设内容
  • 光明新区城市建设局网站长沙营销型网站制作费用