文章目录
-
- 在当今数字化时代,将内容管理系统与物联网设备集成已成为许多企业的需求。WordPress作为全球最流行的CMS平台,通过定制插件可以与各种物联网设备进行通信,实现数据采集、设备控制和状态监控等功能。本教程将指导您开发一个WordPress插件,用于小批量物联网设备集成,特别适合中小型企业或特定场景应用。
- 在开始开发之前,请确保您的环境满足以下要求: WordPress 5.0+ 安装 PHP 7.4+ 运行环境 MySQL 5.6+ 或 MariaDB 10.1+ 支持HTTPS的服务器环境(物联网通信安全需要) 基本的PHP和JavaScript知识
- 首先,我们创建插件的基本文件结构: iot-device-integration/ ├── iot-device-integration.php # 主插件文件 ├── includes/ │ ├── class-device-manager.php # 设备管理类 │ ├── class-api-handler.php # API处理类 │ └── class-data-processor.php # 数据处理类 ├── admin/ │ ├── css/ │ │ └── admin-style.css # 后台样式 │ ├── js/ │ │ └── admin-script.js # 后台脚本 │ └── partials/ │ └── admin-display.php # 后台界面 ├── public/ │ ├── css/ │ │ └── public-style.css # 前台样式 │ ├── js/ │ │ └── public-script.js # 前台脚本 │ └── partials/ │ └── public-display.php # 前台显示 └── uninstall.php # 卸载清理脚本
- 创建主插件文件 iot-device-integration.php: <?php /** * Plugin Name: IoT设备集成插件 * Plugin URI: https://yourwebsite.com/iot-plugin * Description: 小批量物联网设备与WordPress集成解决方案 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later * Text Domain: iot-device-integration */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('IOT_PLUGIN_VERSION', '1.0.0'); define('IOT_PLUGIN_PATH', plugin_dir_path(__FILE__)); define('IOT_PLUGIN_URL', plugin_dir_url(__FILE__)); define('IOT_PLUGIN_BASENAME', plugin_basename(__FILE__)); // 自动加载类文件 spl_autoload_register(function ($class_name) { $prefix = 'IOT_'; $base_dir = IOT_PLUGIN_PATH . 'includes/'; $len = strlen($prefix); if (strncmp($prefix, $class_name, $len) !== 0) { return; } $relative_class = substr($class_name, $len); $file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php'; if (file_exists($file)) { require_once $file; } }); // 初始化插件 class IoT_Device_Integration { private static $instance = null; private $device_manager; public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { $this->load_dependencies(); $this->init_hooks(); } private function load_dependencies() { require_once IOT_PLUGIN_PATH . 'includes/class-device-manager.php'; require_once IOT_PLUGIN_PATH . 'includes/class-api-handler.php'; require_once IOT_PLUGIN_PATH . 'includes/class-data-processor.php'; $this->device_manager = new IOT_Device_Manager(); } private function init_hooks() { // 激活/停用钩子 register_activation_hook(__FILE__, array($this, 'activate_plugin')); register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin')); // 初始化钩子 add_action('init', array($this, 'init_plugin')); // 后台菜单 add_action('admin_menu', array($this, 'add_admin_menu')); // 加载文本域 add_action('plugins_loaded', array($this, 'load_textdomain')); } public function activate_plugin() { // 创建必要的数据库表 $this->create_database_tables(); // 设置默认选项 $this->set_default_options(); // 刷新重写规则 flush_rewrite_rules(); } public function deactivate_plugin() { // 清理临时数据 // 注意:这里不删除用户数据 flush_rewrite_rules(); } private function create_database_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'iot_devices'; $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, device_id varchar(100) NOT NULL, device_name varchar(255) NOT NULL, device_type varchar(100) NOT NULL, api_key varchar(255) NOT NULL, status varchar(50) DEFAULT 'inactive', last_seen datetime DEFAULT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY device_id (device_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } private function set_default_options() { if (!get_option('iot_plugin_settings')) { $default_settings = array( 'api_enabled' => true, 'api_auth_required' => true, 'data_retention_days' => 30, 'max_devices' => 50, 'debug_mode' => false ); update_option('iot_plugin_settings', $default_settings); } } public function init_plugin() { // 初始化API处理器 $api_handler = new IOT_API_Handler(); $api_handler->register_routes(); } public function add_admin_menu() { add_menu_page( 'IoT设备管理', 'IoT设备', 'manage_options', 'iot-devices', array($this, 'display_admin_page'), 'dashicons-admin-generic', 30 ); add_submenu_page( 'iot-devices', '设备设置', '设置', 'manage_options', 'iot-device-settings', array($this, 'display_settings_page') ); } public function display_admin_page() { include_once IOT_PLUGIN_PATH . 'admin/partials/admin-display.php'; } public function display_settings_page() { include_once IOT_PLUGIN_PATH . 'admin/partials/settings-display.php'; } public function load_textdomain() { load_plugin_textdomain( 'iot-device-integration', false, dirname(IOT_PLUGIN_BASENAME) . '/languages' ); } } // 启动插件 function iot_device_integration_init() { return IoT_Device_Integration::get_instance(); } // 延迟初始化以确保WordPress完全加载 add_action('plugins_loaded', 'iot_device_integration_init');
- 创建 includes/class-device-manager.php: <?php /** * 物联网设备管理类 * 负责设备的CRUD操作和状态管理 */ class IOT_Device_Manager { private $table_name; public function __construct() { global $wpdb; $this->table_name = $wpdb->prefix . 'iot_devices'; } /** * 添加新设备 * @param array $device_data 设备数据 * @return int|false 设备ID或false */ public function add_device($device_data) { global $wpdb; $defaults = array( 'device_id' => '', 'device_name' => '', 'device_type' => 'sensor', 'api_key' => $this->generate_api_key(), 'status' => 'inactive', 'last_seen' => current_time('mysql') ); $data = wp_parse_args($device_data, $defaults); // 验证必要字段 if (empty($data['device_id']) || empty($data['device_name'])) { return false; } // 检查设备是否已存在 if ($this->device_exists($data['device_id'])) { return false; } $result = $wpdb->insert( $this->table_name, $data, array('%s', '%s', '%s', '%s', '%s', '%s') ); if ($result) { return $wpdb->insert_id; } return false; } /** * 更新设备最后在线时间 * @param string $device_id 设备ID * @return bool 是否成功 */ public function update_device_heartbeat($device_id) { global $wpdb; return $wpdb->update( $this->table_name, array( 'last_seen' => current_time('mysql'), 'status' => 'active' ), array('device_id' => $device_id), array('%s', '%s'), array('%s') ); } /** * 获取所有设备 * @return array 设备列表 */ public function get_all_devices() { global $wpdb; $query = "SELECT * FROM {$this->table_name} ORDER BY created_at DESC"; return $wpdb->get_results($query, ARRAY_A); } /** * 通过设备ID获取设备 * @param string $device_id 设备ID * @return array|null 设备数据或null */ public function get_device_by_id($device_id) { global $wpdb; $query = $wpdb->prepare( "SELECT * FROM {$this->table_name} WHERE device_id = %s", $device_id ); return $wpdb->get_row($query, ARRAY_A); } /** * 验证API密钥 * @param string $device_id 设备ID * @param string $api_key API密钥 * @return bool 是否验证通过 */ public function validate_api_key($device_id, $api_key) { global $wpdb; $query = $wpdb->prepare( "SELECT COUNT(*) FROM {$this->table_name} WHERE device_id = %s AND api_key = %s", $device_id, $api_key ); $count = $wpdb->get_var($query); return $count > 0; } /** * 检查设备是否存在 * @param string $device_id 设备ID * @return bool 是否存在 */ private function device_exists($device_id) { global $wpdb; $query = $wpdb->prepare( "SELECT COUNT(*) FROM {$this->table_name} WHERE device_id = %s", $device_id ); $count = $wpdb->get_var($query); return $count > 0; } /** * 生成API密钥 * @return string 生成的API密钥 */ private function generate_api_key() { return 'iot_' . bin2hex(random_bytes(16)); } }
- 创建 includes/class-api-handler.php: <?php /** * REST API处理器 * 处理物联网设备的HTTP请求 */ class IOT_API_Handler { private $namespace = 'iot/v1'; public function register_routes() { add_action('rest_api_init', array($this, 'register_api_routes')); } public function register_api_routes() { // 设备数据上报端点 register_rest_route($this->namespace, '/data/(?P<device_id>[a-zA-Z0-9_-]+)', array( 'methods' => 'POST', 'callback' => array($this, 'handle_data_submission'), 'permission_callback' => array($this, 'verify_api_key'), 'args' => array( 'device_id' => array( 'required' => true, 'validate_callback' => function($param) { return is_string($param) && strlen($param) <= 100; } ), ), )); // 设备状态查询端点 register_rest_route($this->namespace, '/status/(?P<device_id>[a-zA-Z0-9_-]+)', array( 'methods' => 'GET', 'callback' => array($this, 'get_device_status'), 'permission_callback' => array($this, 'verify_api_key'), )); // 命令下发端点 register_rest_route($this->namespace, '/command/(?P<device_id>[a-zA-Z0-9_-]+)', array( 'methods' => 'POST', 'callback' => array($this, 'send_command'), 'permission_callback' => array($this, 'verify_api_key'), )); } /** * 处理设备数据上报 * @param WP_REST_Request $request 请求对象 * @return WP_REST_Response 响应 */ public function handle_data_submission(WP_REST_Request $request) { $device_id = $request->get_param('device_id'); $data = $request->get_json_params(); // 更新设备心跳 $device_manager = new IOT_Device_Manager(); $device_manager->update_device_heartbeat($device_id); // 处理接收到的数据 $processor = new IOT_Data_Processor(); $result = $processor->process_device_data($device_id, $data); if ($result) { return new WP_REST_Response(array( 'success' => true, 'message' => '数据接收成功', 'timestamp' => current_time('timestamp'), 'data_id' => $result ), 200); } else { return new WP_REST_Response(array( 'success' => false, 'message' => '数据处理失败' ), 500); } } /** * 获取设备状态 * @param WP_REST_Request $request 请求对象 * @return WP_REST_Response 响应 */ public function get_device_status(WP_REST_Request $request) { $device_id = $request->get_param('device_id'); $device_manager = new IOT_Device_Manager(); $device = $device_manager->get_device_by_id($device_id); if ($device) { return new WP_REST_Response(array( 'success' => true, 'device' => $device ), 200); } else { return new WP_REST_Response(array( 'success' => false, 'message' => '设备未找到' ), 404); } } /** * 发送命令到设备 * @param WP_REST_Request $request 请求对象 * @return WP_REST_Response 响应 */ public function send_command(WP_REST_Request $request) { $device_id = $request->get_param('device_id'); $command = $request->get_json_params(); // 这里可以实现命令队列或直接发送到设备 // 示例:将命令存储到数据库供设备拉取 $result = $this->store_command_for_device($device_id, $command); if ($result) { return new WP_REST_Response(array( 'success' => true, 'message' => '命令已接收', 'command_id' => $result ), 200); } else { return new WP_REST_Response(array( 'success' => false, 'message' => '命令处理失败' ), 500); } } /** * 验证API密钥 * @param WP_REST_Request $request 请求对象 * @return bool 是否验证通过 */ public function verify_api_key(WP_REST_Request $request) { $device_id = $request->get_param('device_id'); $api_key = $request->get_header('X-API-Key'); if (empty($api_key)) { return false; } $device_manager = new IOT_Device_Manager(); return $device_manager->validate_api_key($device_id, $api_key); } /** * 存储设备命令 * @param string $device_id 设备ID * @param array $command 命令数据 * @return int|false 命令ID或false */ private function store_command_for_device($device_id, $command) { global $wpdb; $table_name = $wpdb->prefix . 'iot_commands'; $data = array( 'device_id' => $device_id, 'command' => json_encode($command), 'status' => 'pending', 'created_at' => current_time('mysql') ); $result = $wpdb->insert( $table_name, $data, %s', '%s', '%s') ); return $result ? $wpdb->insert_id : false; } } ## 数据处理类实现 创建 `includes/class-data-processor.php`: <?php/** 物联网数据处理类 负责处理、存储和分析设备数据 */ class IOT_Data_Processor { private $data_table; public function __construct() { global $wpdb; $this->data_table = $wpdb->prefix . 'iot_device_data'; // 确保数据表存在 $this->create_data_table(); } /** * 创建设备数据表 */ private function create_data_table() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE IF NOT EXISTS {$this->data_table} ( id bigint(20) NOT NULL AUTO_INCREMENT, device_id varchar(100) NOT NULL, data_type varchar(50) NOT NULL, value text NOT NULL, unit varchar(20) DEFAULT NULL, recorded_at datetime DEFAULT CURRENT_TIMESTAMP, processed tinyint(1) DEFAULT 0, PRIMARY KEY (id), KEY device_id (device_id), KEY data_type (data_type), KEY recorded_at (recorded_at) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } /** * 处理设备数据 * @param string $device_id 设备ID * @param array $data 设备数据 * @return int|false 数据ID或false */ public function process_device_data($device_id, $data) { global $wpdb; // 验证数据格式 if (!$this->validate_data($data)) { error_log('无效的设备数据格式: ' . json_encode($data)); return false; } // 存储原始数据 $data_id = $this->store_raw_data($device_id, $data); if (!$data_id) { return false; } // 根据数据类型进行特定处理 $this->process_by_data_type($device_id, $data); // 触发数据处理的钩子 do_action('iot_device_data_processed', $device_id, $data, $data_id); return $data_id; } /** * 存储原始数据 * @param string $device_id 设备ID * @param array $data 设备数据 * @return int|false 数据ID或false */ private function store_raw_data($device_id, $data) { global $wpdb; $insert_data = array( 'device_id' => $device_id, 'data_type' => $data['type'] ?? 'unknown', 'value' => json_encode($data), 'unit' => $data['unit'] ?? null, 'recorded_at' => current_time('mysql') ); $result = $wpdb->insert( $this->data_table, $insert_data, array('%s', '%s', '%s', '%s', '%s') ); return $result ? $wpdb->insert_id : false; } /** * 根据数据类型进行特定处理 * @param string $device_id 设备ID * @param array $data 设备数据 */ private function process_by_data_type($device_id, $data) { $data_type = $data['type'] ?? 'unknown'; switch ($data_type) { case 'temperature': $this->process_temperature_data($device_id, $data); break; case 'humidity': $this->process_humidity_data($device_id, $data); break; case 'pressure': $this->process_pressure_data($device_id, $data); break; case 'custom': $this->process_custom_data($device_id, $data); break; default: // 通用数据处理 $this->log_generic_data($device_id, $data); break; } } /** * 处理温度数据 * @param string $device_id 设备ID * @param array $data 温度数据 */ private function process_temperature_data($device_id, $data) { $temperature = floatval($data['value']); // 检查温度是否超出阈值 $thresholds = get_option('iot_temperature_thresholds', array( 'min' => 10, 'max' => 35 )); if ($temperature < $thresholds['min'] || $temperature > $thresholds['max']) { // 触发警报 $this->trigger_alert($device_id, 'temperature', $temperature, $thresholds); } // 更新设备的最新温度 update_option("iot_device_{$device_id}_last_temperature", array( 'value' => $temperature, 'timestamp' => current_time('timestamp'), 'unit' => $data['unit'] ?? '°C' )); } /** * 处理湿度数据 * @param string $device_id 设备ID * @param array $data 湿度数据 */ private function process_humidity_data($device_id, $data) { $humidity = floatval($data['value']); // 更新设备的最新湿度 update_option("iot_device_{$device_id}_last_humidity", array( 'value' => $humidity, 'timestamp' => current_time('timestamp'), 'unit' => $data['unit'] ?? '%' )); } /** * 触发警报 * @param string $device_id 设备ID * @param string $type 数据类型 * @param mixed $value 当前值 * @param array $thresholds 阈值 */ private function trigger_alert($device_id, $type, $value, $thresholds) { $alert_data = array( 'device_id' => $device_id, 'alert_type' => $type . '_threshold', 'current_value' => $value, 'threshold_min' => $thresholds['min'], 'threshold_max' => $thresholds['max'], 'timestamp' => current_time('mysql'), 'status' => 'active' ); // 存储警报 $this->store_alert($alert_data); // 发送通知 $this->send_alert_notification($alert_data); } /** * 存储警报 * @param array $alert_data 警报数据 */ private function store_alert($alert_data) { global $wpdb; $table_name = $wpdb->prefix . 'iot_alerts'; $wpdb->insert( $table_name, $alert_data, array('%s', '%s', '%f', '%f', '%f', '%s', '%s') ); } /** * 发送警报通知 * @param array $alert_data 警报数据 */ private function send_alert_notification($alert_data) { // 获取管理员邮箱 $admin_email = get_option('admin_email'); $subject = sprintf( '[IoT警报] 设备 %s 的%s超出阈值', $alert_data['device_id'], $alert_data['alert_type'] ); $message = sprintf( "设备ID: %sn警报类型: %sn当前值: %sn阈值范围: %s - %sn时间: %s", $alert_data['device_id'], $alert_data['alert_type'], $alert_data['current_value'], $alert_data['threshold_min'], $alert_data['threshold_max'], $alert_data['timestamp'] ); // 发送邮件 wp_mail($admin_email, $subject, $message); // 触发WordPress动作,允许其他插件处理警报 do_action('iot_alert_triggered', $alert_data); } /** * 验证数据格式 * @param array $data 设备数据 * @return bool 是否有效 */ private function validate_data($data) { if (!is_array($data) || empty($data)) { return false; } // 检查必要字段 if (!isset($data['value'])) { return false; } return true; } /** * 获取设备历史数据 * @param string $device_id 设备ID * @param string $data_type 数据类型 * @param int $limit 数据条数限制 * @return array 历史数据 */ public function get_device_history($device_id, $data_type = null, $limit = 100) { global $wpdb; $query = "SELECT * FROM {$this->data_table} WHERE device_id = %s"; $params = array($device_id); if ($data_type) { $query .= " AND data_type = %s"; $params[] = $data_type; } $query .= " ORDER BY recorded_at DESC LIMIT %d"; $params[] = $limit; $prepared_query = $wpdb->prepare($query, $params); return $wpdb->get_results($prepared_query, ARRAY_A); } } ## 后台管理界面开发 创建 `admin/partials/admin-display.php`: <?php/** 后台管理界面 显示设备列表和管理功能 */ // 检查用户权限if (!current_user_can('manage_options')) { wp_die(__('您没有足够的权限访问此页面。', 'iot-device-integration')); } // 获取设备管理器实例$device_manager = new IOT_Device_Manager();$devices = $device_manager->get_all_devices(); // 处理表单提交if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['iot_action'])) { $this->handle_admin_form_submission($_POST); } // 获取插件设置$settings = get_option('iot_plugin_settings', array());?> <div class="wrap"> <h1><?php echo esc_html(get_admin_page_title()); ?></h1> <div class="iot-admin-container"> <!-- 设备概览卡片 --> <div class="iot-overview-cards"> <div class="iot-card"> <h3>总设备数</h3> <p class="iot-card-number"><?php echo count($devices); ?></p> </div> <div class="iot-card"> <h3>在线设备</h3> <p class="iot-card-number"> <?php $active_count = 0; foreach ($devices as $device) { if ($device['status'] === 'active') { $active_count++; } } echo $active_count; ?> </p> </div> <div class="iot-card"> <h3>最大设备数</h3> <p class="iot-card-number"><?php echo esc_html($settings['max_devices'] ?? 50); ?></p> </div> </div> <!-- 添加新设备表单 --> <div class="iot-add-device-form"> <h2>添加新设备</h2> <form method="post" action=""> <?php wp_nonce_field('iot_add_device', 'iot_nonce'); ?> <input type="hidden" name="iot_action" value="add_device"> <table class="form-table"> <tr> <th scope="row"> <label for="device_id">设备ID</label> </th> <td> <input type="text" id="device_id" name="device_id" class="regular-text" required> <p class="description">设备的唯一标识符</p> </td> </tr> <tr> <th scope="row"> <label for="device_name">设备名称</label> </th> <td> <input type="text" id="device_name" name="device_name" class="regular-text" required> </td> </tr> <tr> <th scope="row"> <label for="device_type">设备类型</label> </th> <td> <select id="device_type" name="device_type" class="regular-text"> <option value="sensor">传感器</option> <option value="actuator">执行器</option> <option value="gateway">网关</option> <option value="controller">控制器</option> </select> </td> </tr> </table> <?php submit_button('添加设备'); ?> </form> </div> <!-- 设备列表表格 --> <div class="iot-device-list"> <h2>设备列表</h2> <?php if (empty($devices)): ?> <p>暂无设备,请添加新设备。</p> <?php else: ?> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th>设备ID</th> <th>设备名称</th> <th>类型</th> <th>状态</th> <th>最后在线</th> <th>API密钥</th> <th>操作</th> </tr> </thead> <tbody> <?php foreach ($devices as $device): ?> <tr> <td><?php echo esc_html($device['device_id']); ?></td> <td><?php echo esc_html($device['device_name']); ?></td> <td><?php echo esc_html($device['device_type']); ?></td> <td> <span class="iot-status-badge iot-status-<?php echo esc_attr($device['status']); ?>"> <?php $status_labels = array( 'active' => '在线', 'inactive' => '离线', 'error' => '错误' ); echo esc_html($status_labels[$device['status']] ?? $device['status']); ?> </span> </td> <td> <?php if ($device['last_seen']) { $last_seen = strtotime($device['last_seen']); $time_diff = human_time_diff($last_seen, current_time('timestamp')); echo sprintf(__('%s前', 'iot-device-integration'), $time_diff); } else { echo '从未'; } ?> </td> <td> <code class="iot-api-key"><?php echo esc_html($device['api_key']); ?></code> <button type="button" class="button button-small iot-copy-api-key" data-api-key="<?php echo esc_attr($device['api_key']); ?>"> 复制 </button> </td> <td> <div class="iot-action-buttons"> <button type="button" class="button button-small iot-view-data" data-device-id="<?php echo esc_attr($device['device_id']); ?>"> 查看数据 </button> <form method="post" style="display: inline;"> <?php wp_nonce_field('iot_remove_device', 'iot_nonce'); ?> <input type="hidden" name="iot_action" value="remove_device"> <input type="hidden" name="device_id" value="<?php echo esc_attr($device['device_id']); ?>"> <button type="submit" class="button button-small button-danger" onclick="return confirm('确定要删除此设备吗?');"> 删除 </button> </form> </div> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php endif; ?> </div> <!-- 数据查看模态框 --> <div id="iot-data-modal" class="iot-modal" style="display: none;"> <div class="iot-modal-content"> <div class="iot-modal-header"> <h3>设备数据</h3> <span class="iot-modal-close">×</span> </div> <div class="iot-modal-body"> <div id="iot-data-chart" style="height: 300px;"></div> <div id="iot-data-table"></div> </div> </div> </div> </div> </div> <style>.iot-admin-container { margin-top: 20px; } .iot-overview-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; } .iot-card { background: #fff; border: 1px solid #ccd0d4; border-radius: 4px; padding: 20px; text-align: center; box-shadow: 0 1px 1px rgba(0,0,0,.04); } .iot-card h3 { margin-top: 0; color: #23282d; } .iot-card-number { font-size: 2em; font-weight: bold; color: #0073aa; margin: 10px 0 0; } .iot-status-badge { display: inline-block; padding: 3px 8px; border-radius: 3px; font-size: 12px; font-weight: 600; } .iot-status-active { background-color: #d4edda; color: #155724; } .iot-status-inactive { background-color: #f8d7da; color: #721c24; } .iot-status-error { background-color: #fff3cd; color: #856404; } .iot-api-key { background: #f1f
在当今数字化时代,将内容管理系统与物联网设备集成已成为许多企业的需求。WordPress作为全球最流行的CMS平台,通过定制插件可以与各种物联网设备进行通信,实现数据采集、设备控制和状态监控等功能。本教程将指导您开发一个WordPress插件,用于小批量物联网设备集成,特别适合中小型企业或特定场景应用。
在开始开发之前,请确保您的环境满足以下要求:
- WordPress 5.0+ 安装
- PHP 7.4+ 运行环境
- MySQL 5.6+ 或 MariaDB 10.1+
- 支持HTTPS的服务器环境(物联网通信安全需要)
- 基本的PHP和JavaScript知识
首先,我们创建插件的基本文件结构:
iot-device-integration/
├── iot-device-integration.php # 主插件文件
├── includes/
│ ├── class-device-manager.php # 设备管理类
│ ├── class-api-handler.php # API处理类
│ └── class-data-processor.php # 数据处理类
├── admin/
│ ├── css/
│ │ └── admin-style.css # 后台样式
│ ├── js/
│ │ └── admin-script.js # 后台脚本
│ └── partials/
│ └── admin-display.php # 后台界面
├── public/
│ ├── css/
│ │ └── public-style.css # 前台样式
│ ├── js/
│ │ └── public-script.js # 前台脚本
│ └── partials/
│ └── public-display.php # 前台显示
└── uninstall.php # 卸载清理脚本
创建主插件文件 iot-device-integration.php:
<?php
/**
* Plugin Name: IoT设备集成插件
* Plugin URI: https://yourwebsite.com/iot-plugin
* Description: 小批量物联网设备与WordPress集成解决方案
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
* Text Domain: iot-device-integration
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('IOT_PLUGIN_VERSION', '1.0.0');
define('IOT_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('IOT_PLUGIN_URL', plugin_dir_url(__FILE__));
define('IOT_PLUGIN_BASENAME', plugin_basename(__FILE__));
// 自动加载类文件
spl_autoload_register(function ($class_name) {
$prefix = 'IOT_';
$base_dir = IOT_PLUGIN_PATH . 'includes/';
$len = strlen($prefix);
if (strncmp($prefix, $class_name, $len) !== 0) {
return;
}
$relative_class = substr($class_name, $len);
$file = $base_dir . 'class-' . str_replace('_', '-', strtolower($relative_class)) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
// 初始化插件
class IoT_Device_Integration {
private static $instance = null;
private $device_manager;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->load_dependencies();
$this->init_hooks();
}
private function load_dependencies() {
require_once IOT_PLUGIN_PATH . 'includes/class-device-manager.php';
require_once IOT_PLUGIN_PATH . 'includes/class-api-handler.php';
require_once IOT_PLUGIN_PATH . 'includes/class-data-processor.php';
$this->device_manager = new IOT_Device_Manager();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate_plugin'));
register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin'));
// 初始化钩子
add_action('init', array($this, 'init_plugin'));
// 后台菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载文本域
add_action('plugins_loaded', array($this, 'load_textdomain'));
}
public function activate_plugin() {
// 创建必要的数据库表
$this->create_database_tables();
// 设置默认选项
$this->set_default_options();
// 刷新重写规则
flush_rewrite_rules();
}
public function deactivate_plugin() {
// 清理临时数据
// 注意:这里不删除用户数据
flush_rewrite_rules();
}
private function create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'iot_devices';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
device_id varchar(100) NOT NULL,
device_name varchar(255) NOT NULL,
device_type varchar(100) NOT NULL,
api_key varchar(255) NOT NULL,
status varchar(50) DEFAULT 'inactive',
last_seen datetime DEFAULT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY device_id (device_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
private function set_default_options() {
if (!get_option('iot_plugin_settings')) {
$default_settings = array(
'api_enabled' => true,
'api_auth_required' => true,
'data_retention_days' => 30,
'max_devices' => 50,
'debug_mode' => false
);
update_option('iot_plugin_settings', $default_settings);
}
}
public function init_plugin() {
// 初始化API处理器
$api_handler = new IOT_API_Handler();
$api_handler->register_routes();
}
public function add_admin_menu() {
add_menu_page(
'IoT设备管理',
'IoT设备',
'manage_options',
'iot-devices',
array($this, 'display_admin_page'),
'dashicons-admin-generic',
30
);
add_submenu_page(
'iot-devices',
'设备设置',
'设置',
'manage_options',
'iot-device-settings',
array($this, 'display_settings_page')
);
}
public function display_admin_page() {
include_once IOT_PLUGIN_PATH . 'admin/partials/admin-display.php';
}
public function display_settings_page() {
include_once IOT_PLUGIN_PATH . 'admin/partials/settings-display.php';
}
public function load_textdomain() {
load_plugin_textdomain(
'iot-device-integration',
false,
dirname(IOT_PLUGIN_BASENAME) . '/languages'
);
}
}
// 启动插件
function iot_device_integration_init() {
return IoT_Device_Integration::get_instance();
}
// 延迟初始化以确保WordPress完全加载
add_action('plugins_loaded', 'iot_device_integration_init');
创建 includes/class-device-manager.php:
<?php
/**
* 物联网设备管理类
* 负责设备的CRUD操作和状态管理
*/
class IOT_Device_Manager {
private $table_name;
public function __construct() {
global $wpdb;
$this->table_name = $wpdb->prefix . 'iot_devices';
}
/**
* 添加新设备
* @param array $device_data 设备数据
* @return int|false 设备ID或false
*/
public function add_device($device_data) {
global $wpdb;
$defaults = array(
'device_id' => '',
'device_name' => '',
'device_type' => 'sensor',
'api_key' => $this->generate_api_key(),
'status' => 'inactive',
'last_seen' => current_time('mysql')
);
$data = wp_parse_args($device_data, $defaults);
// 验证必要字段
if (empty($data['device_id']) || empty($data['device_name'])) {
return false;
}
// 检查设备是否已存在
if ($this->device_exists($data['device_id'])) {
return false;
}
$result = $wpdb->insert(
$this->table_name,
$data,
array('%s', '%s', '%s', '%s', '%s', '%s')
);
if ($result) {
return $wpdb->insert_id;
}
return false;
}
/**
* 更新设备最后在线时间
* @param string $device_id 设备ID
* @return bool 是否成功
*/
public function update_device_heartbeat($device_id) {
global $wpdb;
return $wpdb->update(
$this->table_name,
array(
'last_seen' => current_time('mysql'),
'status' => 'active'
),
array('device_id' => $device_id),
array('%s', '%s'),
array('%s')
);
}
/**
* 获取所有设备
* @return array 设备列表
*/
public function get_all_devices() {
global $wpdb;
$query = "SELECT * FROM {$this->table_name} ORDER BY created_at DESC";
return $wpdb->get_results($query, ARRAY_A);
}
/**
* 通过设备ID获取设备
* @param string $device_id 设备ID
* @return array|null 设备数据或null
*/
public function get_device_by_id($device_id) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT * FROM {$this->table_name} WHERE device_id = %s",
$device_id
);
return $wpdb->get_row($query, ARRAY_A);
}
/**
* 验证API密钥
* @param string $device_id 设备ID
* @param string $api_key API密钥
* @return bool 是否验证通过
*/
public function validate_api_key($device_id, $api_key) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table_name}
WHERE device_id = %s AND api_key = %s",
$device_id,
$api_key
);
$count = $wpdb->get_var($query);
return $count > 0;
}
/**
* 检查设备是否存在
* @param string $device_id 设备ID
* @return bool 是否存在
*/
private function device_exists($device_id) {
global $wpdb;
$query = $wpdb->prepare(
"SELECT COUNT(*) FROM {$this->table_name} WHERE device_id = %s",
$device_id
);
$count = $wpdb->get_var($query);
return $count > 0;
}
/**
* 生成API密钥
* @return string 生成的API密钥
*/
private function generate_api_key() {
return 'iot_' . bin2hex(random_bytes(16));
}
}
创建 includes/class-api-handler.php:
<?php
/**
* REST API处理器
* 处理物联网设备的HTTP请求
*/
class IOT_API_Handler {
private $namespace = 'iot/v1';
public function register_routes() {
add_action('rest_api_init', array($this, 'register_api_routes'));
}
public function register_api_routes() {
// 设备数据上报端点
register_rest_route($this->namespace, '/data/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'POST',
'callback' => array($this, 'handle_data_submission'),
'permission_callback' => array($this, 'verify_api_key'),
'args' => array(
'device_id' => array(
'required' => true,
'validate_callback' => function($param) {
return is_string($param) && strlen($param) <= 100;
}
),
),
));
// 设备状态查询端点
register_rest_route($this->namespace, '/status/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'GET',
'callback' => array($this, 'get_device_status'),
'permission_callback' => array($this, 'verify_api_key'),
));
// 命令下发端点
register_rest_route($this->namespace, '/command/(?P<device_id>[a-zA-Z0-9_-]+)', array(
'methods' => 'POST',
'callback' => array($this, 'send_command'),
'permission_callback' => array($this, 'verify_api_key'),
));
}
/**
* 处理设备数据上报
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function handle_data_submission(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$data = $request->get_json_params();
// 更新设备心跳
$device_manager = new IOT_Device_Manager();
$device_manager->update_device_heartbeat($device_id);
// 处理接收到的数据
$processor = new IOT_Data_Processor();
$result = $processor->process_device_data($device_id, $data);
if ($result) {
return new WP_REST_Response(array(
'success' => true,
'message' => '数据接收成功',
'timestamp' => current_time('timestamp'),
'data_id' => $result
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '数据处理失败'
), 500);
}
}
/**
* 获取设备状态
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function get_device_status(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$device_manager = new IOT_Device_Manager();
$device = $device_manager->get_device_by_id($device_id);
if ($device) {
return new WP_REST_Response(array(
'success' => true,
'device' => $device
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '设备未找到'
), 404);
}
}
/**
* 发送命令到设备
* @param WP_REST_Request $request 请求对象
* @return WP_REST_Response 响应
*/
public function send_command(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$command = $request->get_json_params();
// 这里可以实现命令队列或直接发送到设备
// 示例:将命令存储到数据库供设备拉取
$result = $this->store_command_for_device($device_id, $command);
if ($result) {
return new WP_REST_Response(array(
'success' => true,
'message' => '命令已接收',
'command_id' => $result
), 200);
} else {
return new WP_REST_Response(array(
'success' => false,
'message' => '命令处理失败'
), 500);
}
}
/**
* 验证API密钥
* @param WP_REST_Request $request 请求对象
* @return bool 是否验证通过
*/
public function verify_api_key(WP_REST_Request $request) {
$device_id = $request->get_param('device_id');
$api_key = $request->get_header('X-API-Key');
if (empty($api_key)) {
return false;
}
$device_manager = new IOT_Device_Manager();
return $device_manager->validate_api_key($device_id, $api_key);
}
/**
* 存储设备命令
* @param string $device_id 设备ID
* @param array $command 命令数据
* @return int|false 命令ID或false
*/
private function store_command_for_device($device_id, $command) {
global $wpdb;
$table_name = $wpdb->prefix . 'iot_commands';
$data = array(
'device_id' => $device_id,
'command' => json_encode($command),
'status' => 'pending',
'created_at' => current_time('mysql')
);
$result = $wpdb->insert(
$table_name,
$data,
%s', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
}
## 数据处理类实现
创建 `includes/class-data-processor.php`:
<?php
/**
- 物联网数据处理类
- 负责处理、存储和分析设备数据
*/
class IOT_Data_Processor {
private $data_table;
public function __construct() {
global $wpdb;
$this->data_table = $wpdb->prefix . 'iot_device_data';
// 确保数据表存在
$this->create_data_table();
}
/**
* 创建设备数据表
*/
private function create_data_table() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS {$this->data_table} (
id bigint(20) NOT NULL AUTO_INCREMENT,
device_id varchar(100) NOT NULL,
data_type varchar(50) NOT NULL,
value text NOT NULL,
unit varchar(20) DEFAULT NULL,
recorded_at datetime DEFAULT CURRENT_TIMESTAMP,
processed tinyint(1) DEFAULT 0,
PRIMARY KEY (id),
KEY device_id (device_id),
KEY data_type (data_type),
KEY recorded_at (recorded_at)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
/**
* 处理设备数据
* @param string $device_id 设备ID
* @param array $data 设备数据
* @return int|false 数据ID或false
*/
public function process_device_data($device_id, $data) {
global $wpdb;
// 验证数据格式
if (!$this->validate_data($data)) {
error_log('无效的设备数据格式: ' . json_encode($data));
return false;
}
// 存储原始数据
$data_id = $this->store_raw_data($device_id, $data);
if (!$data_id) {
return false;
}
// 根据数据类型进行特定处理
$this->process_by_data_type($device_id, $data);
// 触发数据处理的钩子
do_action('iot_device_data_processed', $device_id, $data, $data_id);
return $data_id;
}
/**
* 存储原始数据
* @param string $device_id 设备ID
* @param array $data 设备数据
* @return int|false 数据ID或false
*/
private function store_raw_data($device_id, $data) {
global $wpdb;
$insert_data = array(
'device_id' => $device_id,
'data_type' => $data['type'] ?? 'unknown',
'value' => json_encode($data),
'unit' => $data['unit'] ?? null,
'recorded_at' => current_time('mysql')
);
$result = $wpdb->insert(
$this->data_table,
$insert_data,
array('%s', '%s', '%s', '%s', '%s')
);
return $result ? $wpdb->insert_id : false;
}
/**
* 根据数据类型进行特定处理
* @param string $device_id 设备ID
* @param array $data 设备数据
*/
private function process_by_data_type($device_id, $data) {
$data_type = $data['type'] ?? 'unknown';
switch ($data_type) {
case 'temperature':
$this->process_temperature_data($device_id, $data);
break;
case 'humidity':
$this->process_humidity_data($device_id, $data);
break;
case 'pressure':
$this->process_pressure_data($device_id, $data);
break;
case 'custom':
$this->process_custom_data($device_id, $data);
break;
default:
// 通用数据处理
$this->log_generic_data($device_id, $data);
break;
}
}
/**
* 处理温度数据
* @param string $device_id 设备ID
* @param array $data 温度数据
*/
private function process_temperature_data($device_id, $data) {
$temperature = floatval($data['value']);
// 检查温度是否超出阈值
$thresholds = get_option('iot_temperature_thresholds', array(
'min' => 10,
'max' => 35
));
if ($temperature < $thresholds['min'] || $temperature > $thresholds['max']) {
// 触发警报
$this->trigger_alert($device_id, 'temperature', $temperature, $thresholds);
}
// 更新设备的最新温度
update_option("iot_device_{$device_id}_last_temperature", array(
'value' => $temperature,
'timestamp' => current_time('timestamp'),
'unit' => $data['unit'] ?? '°C'
));
}
/**
* 处理湿度数据
* @param string $device_id 设备ID
* @param array $data 湿度数据
*/
private function process_humidity_data($device_id, $data) {
$humidity = floatval($data['value']);
// 更新设备的最新湿度
update_option("iot_device_{$device_id}_last_humidity", array(
'value' => $humidity,
'timestamp' => current_time('timestamp'),
'unit' => $data['unit'] ?? '%'
));
}
/**
* 触发警报
* @param string $device_id 设备ID
* @param string $type 数据类型
* @param mixed $value 当前值
* @param array $thresholds 阈值
*/
private function trigger_alert($device_id, $type, $value, $thresholds) {
$alert_data = array(
'device_id' => $device_id,
'alert_type' => $type . '_threshold',
'current_value' => $value,
'threshold_min' => $thresholds['min'],
'threshold_max' => $thresholds['max'],
'timestamp' => current_time('mysql'),
'status' => 'active'
);
// 存储警报
$this->store_alert($alert_data);
// 发送通知
$this->send_alert_notification($alert_data);
}
/**
* 存储警报
* @param array $alert_data 警报数据
*/
private function store_alert($alert_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'iot_alerts';
$wpdb->insert(
$table_name,
$alert_data,
array('%s', '%s', '%f', '%f', '%f', '%s', '%s')
);
}
/**
* 发送警报通知
* @param array $alert_data 警报数据
*/
private function send_alert_notification($alert_data) {
// 获取管理员邮箱
$admin_email = get_option('admin_email');
$subject = sprintf(
'[IoT警报] 设备 %s 的%s超出阈值',
$alert_data['device_id'],
$alert_data['alert_type']
);
$message = sprintf(
"设备ID: %sn警报类型: %sn当前值: %sn阈值范围: %s - %sn时间: %s",
$alert_data['device_id'],
$alert_data['alert_type'],
$alert_data['current_value'],
$alert_data['threshold_min'],
$alert_data['threshold_max'],
$alert_data['timestamp']
);
// 发送邮件
wp_mail($admin_email, $subject, $message);
// 触发WordPress动作,允许其他插件处理警报
do_action('iot_alert_triggered', $alert_data);
}
/**
* 验证数据格式
* @param array $data 设备数据
* @return bool 是否有效
*/
private function validate_data($data) {
if (!is_array($data) || empty($data)) {
return false;
}
// 检查必要字段
if (!isset($data['value'])) {
return false;
}
return true;
}
/**
* 获取设备历史数据
* @param string $device_id 设备ID
* @param string $data_type 数据类型
* @param int $limit 数据条数限制
* @return array 历史数据
*/
public function get_device_history($device_id, $data_type = null, $limit = 100) {
global $wpdb;
$query = "SELECT * FROM {$this->data_table}
WHERE device_id = %s";
$params = array($device_id);
if ($data_type) {
$query .= " AND data_type = %s";
$params[] = $data_type;
}
$query .= " ORDER BY recorded_at DESC LIMIT %d";
$params[] = $limit;
$prepared_query = $wpdb->prepare($query, $params);
return $wpdb->get_results($prepared_query, ARRAY_A);
}
}
## 后台管理界面开发
创建 `admin/partials/admin-display.php`:
<?php
/**
- 后台管理界面
- 显示设备列表和管理功能
*/
// 检查用户权限
if (!current_user_can('manage_options')) {
wp_die(__('您没有足够的权限访问此页面。', 'iot-device-integration'));
}
// 获取设备管理器实例
$device_manager = new IOT_Device_Manager();
$devices = $device_manager->get_all_devices();
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['iot_action'])) {
$this->handle_admin_form_submission($_POST);
}
// 获取插件设置
$settings = get_option('iot_plugin_settings', array());
?>
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="iot-admin-container">
<!-- 设备概览卡片 -->
<div class="iot-overview-cards">
<div class="iot-card">
<h3>总设备数</h3>
<p class="iot-card-number"><?php echo count($devices); ?></p>
</div>
<div class="iot-card">
<h3>在线设备</h3>
<p class="iot-card-number">
<?php
$active_count = 0;
foreach ($devices as $device) {
if ($device['status'] === 'active') {
$active_count++;
}
}
echo $active_count;
?>
</p>
</div>
<div class="iot-card">
<h3>最大设备数</h3>
<p class="iot-card-number"><?php echo esc_html($settings['max_devices'] ?? 50); ?></p>
</div>
</div>
<!-- 添加新设备表单 -->
<div class="iot-add-device-form">
<h2>添加新设备</h2>
<form method="post" action="">
<?php wp_nonce_field('iot_add_device', 'iot_nonce'); ?>
<input type="hidden" name="iot_action" value="add_device">
<table class="form-table">
<tr>
<th scope="row">
<label for="device_id">设备ID</label>
</th>
<td>
<input type="text" id="device_id" name="device_id"
class="regular-text" required>
<p class="description">设备的唯一标识符</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="device_name">设备名称</label>
</th>
<td>
<input type="text" id="device_name" name="device_name"
class="regular-text" required>
</td>
</tr>
<tr>
<th scope="row">
<label for="device_type">设备类型</label>
</th>
<td>
<select id="device_type" name="device_type" class="regular-text">
<option value="sensor">传感器</option>
<option value="actuator">执行器</option>
<option value="gateway">网关</option>
<option value="controller">控制器</option>
</select>
</td>
</tr>
</table>
<?php submit_button('添加设备'); ?>
</form>
</div>
<!-- 设备列表表格 -->
<div class="iot-device-list">
<h2>设备列表</h2>
<?php if (empty($devices)): ?>
<p>暂无设备,请添加新设备。</p>
<?php else: ?>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>设备ID</th>
<th>设备名称</th>
<th>类型</th>
<th>状态</th>
<th>最后在线</th>
<th>API密钥</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php foreach ($devices as $device): ?>
<tr>
<td><?php echo esc_html($device['device_id']); ?></td>
<td><?php echo esc_html($device['device_name']); ?></td>
<td><?php echo esc_html($device['device_type']); ?></td>
<td>
<span class="iot-status-badge iot-status-<?php echo esc_attr($device['status']); ?>">
<?php
$status_labels = array(
'active' => '在线',
'inactive' => '离线',
'error' => '错误'
);
echo esc_html($status_labels[$device['status']] ?? $device['status']);
?>
</span>
</td>
<td>
<?php
if ($device['last_seen']) {
$last_seen = strtotime($device['last_seen']);
$time_diff = human_time_diff($last_seen, current_time('timestamp'));
echo sprintf(__('%s前', 'iot-device-integration'), $time_diff);
} else {
echo '从未';
}
?>
</td>
<td>
<code class="iot-api-key"><?php echo esc_html($device['api_key']); ?></code>
<button type="button" class="button button-small iot-copy-api-key"
data-api-key="<?php echo esc_attr($device['api_key']); ?>">
复制
</button>
</td>
<td>
<div class="iot-action-buttons">
<button type="button" class="button button-small iot-view-data"
data-device-id="<?php echo esc_attr($device['device_id']); ?>">
查看数据
</button>
<form method="post" style="display: inline;">
<?php wp_nonce_field('iot_remove_device', 'iot_nonce'); ?>
<input type="hidden" name="iot_action" value="remove_device">
<input type="hidden" name="device_id" value="<?php echo esc_attr($device['device_id']); ?>">
<button type="submit" class="button button-small button-danger"
onclick="return confirm('确定要删除此设备吗?');">
删除
</button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<!-- 数据查看模态框 -->
<div id="iot-data-modal" class="iot-modal" style="display: none;">
<div class="iot-modal-content">
<div class="iot-modal-header">
<h3>设备数据</h3>
<span class="iot-modal-close">×</span>
</div>
<div class="iot-modal-body">
<div id="iot-data-chart" style="height: 300px;"></div>
<div id="iot-data-table"></div>
</div>
</div>
</div>
</div>
</div>
<style>
.iot-admin-container {
margin-top: 20px;
}
.iot-overview-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.iot-card {
background: #fff;
border: 1px solid #ccd0d4;
border-radius: 4px;
padding: 20px;
text-align: center;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.iot-card h3 {
margin-top: 0;
color: #23282d;
}
.iot-card-number {
font-size: 2em;
font-weight: bold;
color: #0073aa;
margin: 10px 0 0;
}
.iot-status-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 3px;
font-size: 12px;
font-weight: 600;
}
.iot-status-active {
background-color: #d4edda;
color: #155724;
}
.iot-status-inactive {
background-color: #f8d7da;
color: #721c24;
}
.iot-status-error {
background-color: #fff3cd;
color: #856404;
}
.iot-api-key {
background: #f1f


