All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.foxtech.device.service.controller.DeviceExecuteController Maven / Gradle / Ivy

The newest version!
/* ----------------------------------------------------------------------------
 * Copyright (c) Guangzhou Fox-Tech Co., Ltd. 2020-2024. All rights reserved.
 *
 *     This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 * --------------------------------------------------------------------------- */
 
package cn.foxtech.device.service.controller;

import cn.foxtech.common.domain.constant.RedisStatusConstant;
import cn.foxtech.common.entity.entity.DeviceEntity;
import cn.foxtech.common.entity.entity.OperateEntity;
import cn.foxtech.common.rpc.redis.device.server.RedisListDeviceServer;
import cn.foxtech.common.rpc.redis.persist.client.RedisListPersistClient;
import cn.foxtech.common.status.ServiceStatus;
import cn.foxtech.common.utils.scheduler.singletask.PeriodTaskService;
import cn.foxtech.core.exception.ServiceException;
import cn.foxtech.device.domain.constant.DeviceMethodVOFieldConstant;
import cn.foxtech.device.domain.vo.OperateRequestVO;
import cn.foxtech.device.domain.vo.OperateRespondVO;
import cn.foxtech.device.domain.vo.TaskRequestVO;
import cn.foxtech.device.domain.vo.TaskRespondVO;
import cn.foxtech.device.protocol.v1.core.annotation.FoxEdgeOperate;
import cn.foxtech.device.service.service.EntityManageService;
import cn.foxtech.device.service.service.OperateService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.naming.CommunicationException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 设备执行操作控制器:处理上层应用对设备的操作请求,包括批量操作/单步操作/发布操作
 */
@Component
public class DeviceExecuteController extends PeriodTaskService {
    private static final Logger logger = Logger.getLogger(DeviceExecuteController.class);

    /**
     * 实体管理
     */
    @Autowired
    EntityManageService entityManageService;

    /**
     * 操作服务
     */
    @Autowired
    private OperateService operateService;

    @Autowired
    private ServiceStatus serviceStatus;

    @Autowired
    private RedisListDeviceServer deviceServer;

    @Autowired
    private RedisListPersistClient persistService;

    /**
     * 执行任务
     *
     * @param threadId 线程ID
     * @throws Exception 异常信息
     */
    public void execute(long threadId) throws Exception {
        // 检查:是否装载完毕
        if (!this.entityManageService.isInitialized()) {
            Thread.sleep(1000);
            return;
        }

        TaskRequestVO taskRequestVO = this.deviceServer.popDeviceRequest(1, TimeUnit.SECONDS);
        if (taskRequestVO == null) {
            return;
        }

        TaskRespondVO taskRespondVO = new TaskRespondVO();
        taskRespondVO.bindBaseVO(taskRequestVO);

        // 逐个步骤的操作设备
        List deviceRequestVOS = taskRequestVO.getRequestVOS();
        for (OperateRequestVO operateRequestVO : deviceRequestVOS) {
            // 执行操作
            OperateRespondVO operateRespondVO = this.execute(operateRequestVO);
            taskRespondVO.getRespondVOS().add(operateRespondVO);
        }


        // 返回数据设备服务
        this.deviceServer.pushDeviceRespond(taskRespondVO.getUuid(), taskRespondVO);

        // 记录用户操作:发送给持久化服务
        this.recordOperate(taskRespondVO);
    }


    /**
     * 单步操作
     *
     * @param requestVO 结构化的请求
     * @return 结构化的响应
     */
    private OperateRespondVO execute(OperateRequestVO requestVO) {
        // 单步操作的参数
        String deviceName = requestVO.getDeviceName();
        String operateName = requestVO.getOperateName();
        Integer timeout = requestVO.getTimeout();


        DeviceEntity deviceEntity = null;
        try {
            // 获得设备详细信息
            deviceEntity = this.entityManageService.getDeviceEntity(deviceName);
            if (deviceEntity == null) {
                throw new ServiceException("指定名称的设备不存在:" + deviceName);
            }

            // 获得操作实体
            OperateEntity find = new OperateEntity();
            find.setManufacturer(deviceEntity.getManufacturer());
            find.setDeviceType(deviceEntity.getDeviceType());
            find.setOperateName(operateName);
            OperateEntity operateEntity = this.entityManageService.getEntity(find.makeServiceKey(), OperateEntity.class);
            if (operateEntity == null) {
                throw new ServiceException("指定的操作,不存在!:" + deviceName);
            }

            // 通过时间戳,判断通道服务是否正在运行
            if (!this.serviceStatus.isActive(RedisStatusConstant.value_model_type_channel, deviceEntity.getChannelType(), 60 * 1000)) {
                throw new ServiceException("指定的Channel服务尚未运行:" + deviceEntity.getChannelType());
            }

            // 组合参数:先组合设备上的参数,再组合操作上的参数,也就是操作参数的优先级高于设备上的参数
            Map param = new HashMap<>();
            param.putAll(deviceEntity.getDeviceParam());
            if (requestVO.getParam() != null) {
                param.putAll(requestVO.getParam());
            }

            // 交换类操作
            if (DeviceMethodVOFieldConstant.value_operate_exchange.equals(requestVO.getOperateMode())) {
                // 执行请求操作
                Map value = this.operateService.smplExchange(deviceName, operateEntity, param, timeout);
                Map status = OperateRespondVO.buildCommonStatus(System.currentTimeMillis(), 0, 0);

                OperateRespondVO respondVO = new OperateRespondVO();
                respondVO.bindBaseVO(requestVO);
                respondVO.setDeviceType(deviceEntity.getDeviceType());
                respondVO.setManufacturer(deviceEntity.getManufacturer());
                respondVO.setData(value, status);
                return respondVO;
            }

            // 发布类操作
            if (DeviceMethodVOFieldConstant.value_operate_publish.equals(requestVO.getOperateMode())) {
                // 执行请求操作
                this.operateService.smplPublish(deviceName, operateEntity, param, timeout);

                OperateRespondVO respondVO = new OperateRespondVO();
                respondVO.bindBaseVO(requestVO);

                return respondVO;
            }

            throw new ServiceException("不支持的操作类型");
        } catch (CommunicationException e) {
            // 通信失败的时候,发送一个通信失败的通知给管理服务
            this.notifyDeviceTimeOut(deviceEntity, requestVO);

            // 返回失败信息给请求的来源
            return this.makeExceptionRespondVO(requestVO, e.getMessage());
        } catch (Exception e) {
            // 返回失败信息给请求的来源
            return this.makeExceptionRespondVO(requestVO, e.getMessage());
        }
    }

    private void notifyDeviceTimeOut(DeviceEntity deviceEntity, OperateRequestVO requestVO) {
        if (deviceEntity == null) {
            return;
        }
    }

    /**
     * 生成返回的数据结构
     *
     * @param requestVO    请求消息
     * @param errorMessage 响应消息
     * @return
     */
    private OperateRespondVO makeExceptionRespondVO(OperateRequestVO requestVO, String errorMessage) {
        // 通信失败:通过通信状态字段告知外部
        Map status = OperateRespondVO.buildCommonStatus(0, System.currentTimeMillis(), 1);

        OperateRespondVO respondVO = OperateRespondVO.error(errorMessage);
        respondVO.bindBaseVO(requestVO);
        respondVO.setData(new HashMap<>(), status);

        return respondVO;
    }


    private void recordOperate(TaskRespondVO taskRespondVO) {
        try {
            // 筛选:是否有data/value/result属性,如果有的话,这个属性是要独立上报的
            List respondVOS = new ArrayList<>();
            for (OperateRespondVO operateRespondVO : taskRespondVO.getRespondVOS()) {
                // 场景1:用户手动标识的要求记录的数据
                if (Boolean.TRUE.equals(operateRespondVO.getRecord())) {
                    // 复制一个副本,并重新填入数据
                    OperateRespondVO resultVO = new OperateRespondVO();
                    resultVO.bind(operateRespondVO);
                    resultVO.setRecord(true);

                    // 打入包裹
                    respondVOS.add(resultVO);
                    continue;
                }
                // 场景2:解码器要求强制记录的数据
                Map values = (Map) operateRespondVO.getData().get(DeviceMethodVOFieldConstant.value_data_value);
                if (values != null && values.containsKey(FoxEdgeOperate.result)) {
                    // 复制一个副本,并重新填入数据
                    OperateRespondVO resultVO = new OperateRespondVO();
                    resultVO.bind(operateRespondVO);
                    resultVO.setRecord(true);

                    // 打入包裹
                    respondVOS.add(resultVO);
                    continue;
                }
            }

            // 检查:是否有真正需要记录的操作
            if (respondVOS.isEmpty()) {
                return;
            }

            // 把数据内容,填写为新的操作步骤
            taskRespondVO.setRespondVOS(respondVOS);

            // 推送数据到持久化服务
            this.persistService.pushRecordRequest(taskRespondVO);
        } catch (Exception e) {
            logger.error(e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy