| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- const pool = require('../config/db');
- const logger = require('../logger'); // 引入日志记录器
- const mqtt = require('../mqttClient'); // 从根目录引入
- const client = mqtt.client; // 根据你的导出方式调整
- // 新增设备查询方法
- getDevices: async (req, res) => {
- try {
- const fields = req.query.fields || 'device_id,name,model,system_version,status'
- const [results] = await pool.promise().query(`
- SELECT ${fields}
- FROM devices
- WHERE system_version IS NOT NULL
- `)
- res.json(results)
- } catch (error) {
- logger.error('获取设备列表失败:', error)
- res.status(500).json({ code: 500, message: '服务器内部错误' })
- }
- }
- const getDevices = (req, res) => {
- logger.info('开始获取所有设备信息');
- const query = `
- SELECT
- d.id, d.device_id, d.room_id, r.room_name, d.status, d.last_seen, d.name,
- d.temperature, d.upload_time, d.switch_status, d.switch_status_time,
- d.level_status, d.level_status_time, d.bound_device_id, d.bound_time,
- d.first_online_time, d.last_online_time, d.last_offline_time, d.ip_address
- FROM devices d
- LEFT JOIN rooms r ON d.room_id = r.id
- `;
- pool.query(query, (err, results) => {
- if (err) {
- logger.error('查询所有设备失败:', err);
- return res.status(500).send('Error querying devices');
- }
- logger.info(`成功获取 ${results.length} 个设备信息`);
- res.status(200).json(results);
- });
- };
- // 绑定设备到房间
- const bindDeviceToRoom = (req, res) => {
- const { deviceId, roomId } = req.body;
- logger.info(`尝试绑定设备 ${deviceId} 到房间 ${roomId}`);
- if (!deviceId || !roomId) {
- logger.warn('绑定设备失败:设备 ID 和房间 ID 不能为空');
- return res.status(400).json({ success: false, message: '设备 ID 和房间 ID 不能为空' });
- }
- const isRelayDevice = deviceId.includes('ESP32');
- if (isRelayDevice) {
- // 检查房间是否已经绑定了继电器
- const checkRelayQuery = `
- SELECT device_id
- FROM devices
- WHERE room_id = ? AND device_id LIKE '%ESP32%'
- `;
- pool.query(checkRelayQuery, [roomId], (err, results) => {
- if (err) {
- logger.error('检查继电器设备失败:', err);
- return res.status(500).json({ success: false, message: '检查继电器设备时出错' });
- }
- if (results.length > 0) {
- logger.warn(`绑定设备失败:房间 ${roomId} 已经绑定了继电器`);
- return res.status(400).json({ success: false, message: '该房间已经绑定了继电器,无法再次绑定' });
- }
- // 执行绑定操作
- executeBinding(deviceId, roomId, res);
- });
- } else {
- // 非继电器设备直接执行绑定
- executeBinding(deviceId, roomId, res);
- }
- };
- // 辅助函数:执行设备绑定
- const executeBinding = (deviceId, roomId, res) => {
- // 首先获取房间名称
- const getRoomNameQuery = 'SELECT room_name FROM rooms WHERE id = ?';
-
- pool.query(getRoomNameQuery, [roomId], (err, roomResults) => {
- if (err) {
- logger.error('获取房间名称失败:', err);
- return res.status(500).json({ success: false, message: '获取房间名称时出错' });
- }
- if (roomResults.length === 0) {
- logger.warn(`房间 ${roomId} 不存在`);
- return res.status(404).json({ success: false, message: '房间不存在' });
- }
- const roomName = roomResults[0].room_name;
- // 更新设备表中的 room_id 和 room_name
- const bindQuery = 'UPDATE devices SET room_id = ?, room_name = ? WHERE device_id = ?';
-
- pool.query(bindQuery, [roomId, roomName, deviceId], (err, results) => {
- if (err) {
- logger.error('绑定设备失败:', err);
- return res.status(500).json({ success: false, message: '绑定设备时出错' });
- }
- if (results.affectedRows === 0) {
- logger.warn(`设备 ${deviceId} 不存在或已绑定到相同房间`);
- return res.status(404).json({ success: false, message: '设备不存在或已绑定到相同房间' });
- }
- logger.info(`设备 ${deviceId} 成功绑定到房间 ${roomId}`);
- res.status(200).json({ success: true, message: '设备绑定成功' });
- });
- });
- };
- // 解绑设备
- const unbindDevice = (req, res) => {
- const { deviceId } = req.params;
- logger.info(`尝试解绑设备: ${deviceId}`);
- const query = 'UPDATE devices SET room_id = NULL, room_name = NULL WHERE device_id = ?';
- pool.query(query, [deviceId], (err, results) => {
- if (err) {
- logger.error('解绑设备失败:', err);
- return res.status(500).send('Error unbinding device');
- }
- logger.info(`设备 ${deviceId} 解绑成功`);
- res.status(200).send('设备已从房间中移除');
- });
- };
- // 删除设备
- const deleteDevice = (req, res) => {
- const { deviceId } = req.params;
- logger.info(`尝试删除设备: ${deviceId}`);
- const query = 'DELETE FROM devices WHERE device_id = ?';
- pool.query(query, [deviceId], (err, results) => {
- if (err) {
- logger.error('删除设备失败:', err);
- return res.status(500).send('Error deleting device');
- }
- logger.info(`设备 ${deviceId} 删除成功`);
- res.status(200).send('设备删除成功');
- });
- };
- // 更新设备信息
- const updateDevice = async (req, res) => {
- const { deviceId, name, roomId } = req.body;
- logger.info(`尝试更新设备信息: deviceId=${deviceId}, name=${name}, roomId=${roomId}`);
- try {
- // 检查设备类型
- const deviceQuery = 'SELECT device_id FROM devices WHERE device_id = ?';
- const [deviceResults] = await pool.promise().query(deviceQuery, [deviceId]);
- if (deviceResults.length === 0) {
- logger.warn(`设备 ${deviceId} 不存在`);
- return res.status(404).json({ success: false, message: '设备不存在' });
- }
- // 如果是继电器设备,检查目标房间是否已有其他继电器
- if (deviceId.includes('ESP32')) {
- const relayQuery = `
- SELECT device_id
- FROM devices
- WHERE room_id = ? AND device_id LIKE "%ESP32%" AND device_id != ?
- `;
- const [relayResults] = await pool.promise().query(relayQuery, [roomId, deviceId]);
- if (relayResults.length > 0) {
- logger.warn(`房间 ${roomId} 已绑定其他继电器`);
- return res.status(400).json({ success: false, message: '该房间已绑定其他继电器' });
- }
- }
- // 获取房间名称
- let roomName = null;
- if (roomId) {
- const roomQuery = 'SELECT room_name FROM rooms WHERE id = ?';
- const [roomResults] = await pool.promise().query(roomQuery, [roomId]);
- if (roomResults.length > 0) {
- roomName = roomResults[0].room_name;
- } else {
- logger.warn(`房间 ${roomId} 不存在`);
- return res.status(404).json({ success: false, message: '房间不存在' });
- }
- }
- // 更新设备信息,包括房间名称
- const updateQuery = 'UPDATE devices SET name = ?, room_id = ?, room_name = ? WHERE device_id = ?';
- await pool.promise().query(updateQuery, [name, roomId, roomName, deviceId]);
- logger.info(`成功更新设备信息: deviceId=${deviceId}, roomName=${roomName}`);
- res.status(200).json({ success: true, message: '设备信息更新成功' });
- } catch (err) {
- logger.error('更新设备信息失败:', err);
- res.status(500).json({ success: false, message: '更新设备信息失败' });
- }
- };
- // 获取设备状态
- const getDeviceStatus = (req, res) => {
- logger.info('开始获取设备状态信息');
- const query = `
- SELECT
- d.device_id,
- d.status AS device_status,
- rs.state AS relay_state,
- rs.temperature,
- rs.timestamp
- FROM devices d
- LEFT JOIN relay_state rs ON d.device_id = rs.device_id
- ORDER BY rs.timestamp DESC
- `;
- pool.query(query, (err, results) => {
- if (err) {
- logger.error('查询设备状态失败:', err);
- return res.status(500).send('Error querying device status');
- }
- logger.info(`成功获取 ${results.length} 个设备的状态信息`);
- res.status(200).json(results);
- });
- };
- // 设备管理界面查询绑定状态
- const getDevicesByRoom = (req, res) => {
- const { roomId } = req.query;
- logger.info(`开始获取房间 ${roomId} 的设备信息`);
- if (!roomId) {
- logger.warn('获取设备失败:房间ID为空');
- return res.status(400).send('房间 ID 不能为空');
- }
- const query = `
- SELECT
- device_id,
- name,
- status,
- temperature,
- switch_status,
- level_status
- FROM devices
- WHERE room_id = ?
- `;
- pool.query(query, [roomId], (err, results) => {
- if (err) {
- logger.error(`获取房间 ${roomId} 的设备失败:`, err);
- return res.status(500).send('Error querying devices by room');
- }
- logger.info(`成功获取房间 ${roomId} 的 ${results.length} 个设备信息`);
- res.status(200).json(results);
- });
- };
- // 设备管理在线状态
- const getDeviceStatusByRoom = (req, res) => {
- const { roomId } = req.query;
- logger.info(`开始获取房间 ${roomId} 的设备状态`);
- if (!roomId) {
- logger.warn('获取设备状态失败:房间ID为空');
- return res.status(400).send('房间 ID 不能为空');
- }
- const query = `
- SELECT
- d.device_id,
- d.status AS device_status,
- rs.state AS relay_state,
- rs.temperature,
- rs.timestamp
- FROM devices d
- LEFT JOIN relay_state rs ON d.device_id = rs.device_id
- WHERE d.room_id = ?
- ORDER BY rs.timestamp DESC
- `;
- pool.query(query, [roomId], (err, results) => {
- if (err) {
- logger.error(`获取房间 ${roomId} 的设备状态失败:`, err);
- return res.status(500).send('Error querying device status');
- }
- logger.info(`成功获取房间 ${roomId} 的 ${results.length} 个设备状态`);
- res.status(200).json(results);
- });
- };
- // 获取 GPIO 状态
- const getGpioState = (req, res) => {
- const { deviceId } = req.query;
- logger.info(`开始获取设备 ${deviceId} 的GPIO状态`);
- if (!deviceId) {
- logger.warn('获取GPIO状态失败:设备ID为空');
- return res.status(400).send('设备 ID 不能为空');
- }
- const query = `
- SELECT state
- FROM gpio_state
- WHERE device_id = ?
- ORDER BY timestamp DESC
- LIMIT 1
- `;
- pool.query(query, [deviceId], (err, results) => {
- if (err) {
- logger.error(`获取设备 ${deviceId} 的GPIO状态失败:`, err);
- return res.status(500).send('Error querying GPIO state');
- }
- logger.info(`成功获取设备 ${deviceId} 的GPIO状态`);
- res.status(200).json(results[0] || { state: 'low' });
- });
- };
- // 绑定继电器到人体传感器
- const bindRelayToSensor = async (req, res) => {
- const { sensorId, roomId } = req.body;
- logger.info(`尝试绑定房间 ${roomId} 的继电器到传感器 ${sensorId}`);
- if (!sensorId || !roomId) {
- logger.warn('绑定失败:传感器ID或房间ID为空');
- return res.status(400).json({ success: false, message: '传感器ID和房间ID不能为空' });
- }
- try {
- // 查询房间中的继电器设备
- const relayQuery = `
- SELECT device_id
- FROM devices
- WHERE room_id = ? AND device_id LIKE '%ESP32%'
- `;
- const [relayResults] = await pool.promise().query(relayQuery, [roomId]);
- if (relayResults.length === 0) {
- logger.warn(`房间 ${roomId} 没有继电器设备`);
- return res.status(404).json({ success: false, message: '该房间没有继电器设备' });
- }
- const relayId = relayResults[0].device_id;
- logger.info(`找到继电器设备: ${relayId}`);
- // 更新人体传感器模块的 bound_device_id 和 bound_time
- const updateQuery = `
- UPDATE devices
- SET bound_device_id = ?, bound_time = NOW()
- WHERE device_id = ?
- `;
- await pool.promise().query(updateQuery, [relayId, sensorId]);
- // 通过 MQTT 发送继电器 ID
- const controlTopic = `device/${sensorId}/control`;
- client.publish(controlTopic, relayId, { qos: 1 }, (err) => { // 添加了 qos: 1 确保消息可靠传递
- if (err) {
- logger.error('MQTT消息发送失败:', err);
- return res.status(500).json({ success: false, message: 'MQTT 消息发布失败' });
- }
-
- logger.info(`成功绑定并配置继电器: 传感器=${sensorId}, 继电器=${relayId}`);
- res.status(200).json({
- success: true,
- message: '继电器与传感器绑定成功,并已发送配置信息'
- });
- });
- } catch (error) {
- logger.error('绑定继电器到传感器失败:', error);
- res.status(500).json({ success: false, message: '处理绑定请求时出错' });
- }
- };
- // 新增:获取所有房间及其设备信息
- const getAllRoomsWithDevices = async (req, res) => {
- logger.info('开始获取所有房间及其设备信息');
-
- const query = `
- SELECT
- r.id AS room_id,
- r.room_name,
- r.orientation,
- d.id AS device_id,
- d.device_id AS device_uid,
- d.status,
- d.temperature,
- d.switch_status,
- d.level_status
- FROM rooms r
- LEFT JOIN devices d ON r.id = d.room_id
- ORDER BY r.id
- `;
- pool.query(query, (err, results) => {
- if (err) {
- logger.error('获取房间和设备信息失败:', err);
- return res.status(500).send('Error querying rooms and devices');
- }
-
- // 将结果按房间分组
- const roomsMap = new Map();
- results.forEach(row => {
- if (!roomsMap.has(row.room_id)) {
- roomsMap.set(row.room_id, {
- id: row.room_id,
- room_name: row.room_name,
- orientation: row.orientation,
- devices: []
- });
- }
- if (row.device_id) {
- roomsMap.get(row.room_id).devices.push({
- device_id: row.device_uid,
- status: row.status,
- temperature: row.temperature,
- switch_status: row.switch_status,
- level_status: row.level_status
- });
- }
- });
- const rooms = Array.from(roomsMap.values());
- logger.info(`成功获取 ${rooms.length} 个房间及其设备信息`);
- res.status(200).json(rooms);
- });
- };
- module.exports = {
- getDevices,
- bindDeviceToRoom,
- unbindDevice,
- deleteDevice,
- updateDevice,
- getDeviceStatus,
- getDeviceStatusByRoom,
- getDevicesByRoom,
- getGpioState,
- bindRelayToSensor,
- getAllRoomsWithDevices
- };
|