如何将Python充电状态检测脚本的输出发送至PHP服务器?
Hey there! Let's walk through how to send your charger status data from your Python script to a PHP server, and set up remote access to that data. Here's a step-by-step solution that fits right into your existing code:
1. Modify Your Python Script to Send Data to the PHP Server
First, we'll add HTTP request functionality to your script using the requests library (it's simpler than built-in modules for this task). Here's the updated version of your code with data-sending logic:
import os import ctypes import time from ctypes import wintypes import winsound import socket import requests # 新增:导入requests库 class SYSTEM_POWER_STATUS(ctypes.Structure): _fields_ = [ ('ACLineStatus', wintypes.BYTE), ('BatteryFlag', wintypes.BYTE), ('BatteryLifePercent', wintypes.BYTE), ('BatteryLifeTime', wintypes.DWORD), ('BatteryFullLifeTime', wintypes.DWORD), ] # 替换成你的PHP服务器地址(比如http://your-domain.com/receive-status.php) SERVER_URL = "http://your-server-address/receive-status.php" # 可选:添加API密钥防止非法提交(推荐用于公网服务器) API_KEY = "your-secret-api-key-here" print(socket.gethostname()) SYSTEM_POWER_STATUS_P = ctypes.POINTER(SYSTEM_POWER_STATUS) GetSystemPowerStatus = ctypes.windll.kernel32.GetSystemPowerStatus GetSystemPowerStatus.argtypes = [SYSTEM_POWER_STATUS_P] GetSystemPowerStatus.restype = wintypes.BOOL status = SYSTEM_POWER_STATUS() while True: try: if not GetSystemPowerStatus(ctypes.pointer(status)): raise ctypes.WinError() # 打印本地状态 ac_status = "YES" if status.ACLineStatus == 1 else "NO" print('Charger Connected: ', ac_status) if status.ACLineStatus == 0: winsound.Beep(2000, 1000) battery_removed = "Yes" if status.BatteryFlag == -128 else "No" if status.BatteryFlag == -128: print('Battery removed: ', battery_removed) winsound.Beep(2000, 1000) # 恢复系统音量 cmd = 'nircmd.exe mutesysvolume 0 && nircmd.exe setsysvolume 65535' os.system(cmd) # 准备要发送到服务器的数据包 payload = { "hostname": socket.gethostname(), "ac_line_status": status.ACLineStatus, "battery_flag": status.BatteryFlag, "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"), "api_key": API_KEY # 可选:身份验证字段 } # 发送POST请求到服务器 response = requests.post(SERVER_URL, data=payload, timeout=5) # 可选:打印服务器响应用于调试 # print("Server response:", response.text) except requests.exceptions.RequestException as e: # 处理网络异常,避免脚本崩溃 print(f"Failed to send data to server: {e}") except Exception as e: print(f"Unexpected error: {e}") # 调整发送频率(建议每5-10秒一次,减少服务器压力) time.sleep(5)
Before running this, install the requests library with:
pip install requests
2. Create the PHP Server Script to Receive and Store Data
Next, make a receive-status.php file on your web server. This script will accept the data from your Python client and store it in a MySQL database (you can use other databases too, but MySQL is common for PHP setups).
Step 2.1: Set Up the Database Table
First, create a database and table to store the status data. Run this SQL query in your MySQL admin tool (like phpMyAdmin):
CREATE TABLE device_status ( id INT AUTO_INCREMENT PRIMARY KEY, hostname VARCHAR(255) NOT NULL, ac_line_status TINYINT NOT NULL, battery_flag TINYINT NOT NULL, timestamp DATETIME NOT NULL );
Step 2.2: Write the Receive Script
<?php // 替换为你的数据库配置 $servername = "localhost"; $db_username = "your-db-username"; $db_password = "your-db-password"; $db_name = "your-db-name"; $valid_api_key = "your-secret-api-key-here"; // 和Python脚本中的API_KEY一致 // 建立数据库连接 $conn = new mysqli($servername, $db_username, $db_password, $db_name); if ($conn->connect_error) { die("Database connection failed: " . $conn->connect_error); } // 验证API密钥(可选,但推荐) $received_api_key = $_POST['api_key'] ?? ''; if ($received_api_key !== $valid_api_key) { die("Invalid API key"); } // 接收POST数据 $hostname = $_POST['hostname'] ?? ''; $ac_line_status = $_POST['ac_line_status'] ?? -1; $battery_flag = $_POST['battery_flag'] ?? -1; $timestamp = $_POST['timestamp'] ?? ''; // 验证数据有效性 if (!empty($hostname) && !empty($timestamp) && $ac_line_status !== -1) { // 使用预处理语句防止SQL注入 $stmt = $conn->prepare("INSERT INTO device_status (hostname, ac_line_status, battery_flag, timestamp) VALUES (?, ?, ?, ?)"); $stmt->bind_param("siss", $hostname, $ac_line_status, $battery_flag, $timestamp); if ($stmt->execute()) { echo "Status saved successfully"; } else { echo "Error saving status: " . $stmt->error; } $stmt->close(); } else { echo "Invalid data received"; } $conn->close(); ?>
3. Create a PHP Script for Remote Status Reading
To view the status remotely, make a read-status.php file on your server. This script will fetch the latest status from the database and return it in JSON format (easy to read in a browser or use in other apps):
<?php // 同样的数据库配置 $servername = "localhost"; $db_username = "your-db-username"; $db_password = "your-db-password"; $db_name = "your-db-name"; $conn = new mysqli($servername, $db_username, $db_password, $db_name); if ($conn->connect_error) { die("Database connection failed: " . $conn->connect_error); } // 可选:按主机名筛选(比如http://your-server.com/read-status.php?hostname=YourPCName) $target_hostname = $_GET['hostname'] ?? ''; if (!empty($target_hostname)) { // 获取指定主机的最新状态 $stmt = $conn->prepare("SELECT * FROM device_status WHERE hostname = ? ORDER BY timestamp DESC LIMIT 1"); $stmt->bind_param("s", $target_hostname); } else { // 获取所有主机的最新状态 $stmt = $conn->prepare("SELECT * FROM device_status GROUP BY hostname ORDER BY timestamp DESC"); } $stmt->execute(); $result = $stmt->get_result(); $status_list = []; while ($row = $result->fetch_assoc()) { // 转换状态为易读文本 $row['ac_status_text'] = $row['ac_line_status'] == 1 ? "Charger Connected" : "Charger Disconnected"; $row['battery_text'] = $row['battery_flag'] == -128 ? "Battery Removed" : "Battery Present"; $status_list[] = $row; } // 返回JSON格式数据 header('Content-Type: application/json'); echo json_encode($status_list, JSON_PRETTY_PRINT); $stmt->close(); $conn->close(); ?>
4. Key Notes to Keep in Mind
- Server Accessibility: If your server is on the public internet, ensure it has a public IP/domain and that port 80 (HTTP) or 443 (HTTPS) is open. For local networks, use your server's local IP.
- HTTPS: For public servers, use HTTPS instead of HTTP to encrypt data in transit (you can get free SSL certificates from Let's Encrypt).
- Frequency: Adjust the
time.sleep()value in your Python script to avoid overwhelming the server (5-10 seconds is a good balance). - Error Handling: The Python script includes basic error handling for network issues, so it won't crash if the server is temporarily unavailable.
内容的提问来源于stack exchange,提问作者Monolica

