DeviceBehaviourService.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /*
  2. * +----------------------------------------------------------------------
  3. * | Copyright (c) 奇特物联 2021-2022 All rights reserved.
  4. * +----------------------------------------------------------------------
  5. * | Licensed 未经许可不能去掉「奇特物联」相关版权
  6. * +----------------------------------------------------------------------
  7. * | Author: xw2sy@163.com
  8. * +----------------------------------------------------------------------
  9. */
  10. package cc.iotkit.comps.service;
  11. import cc.iotkit.common.constant.Constants;
  12. import cc.iotkit.common.enums.ErrCode;
  13. import cc.iotkit.common.exception.BizException;
  14. import cc.iotkit.common.utils.DeviceUtil;
  15. import cc.iotkit.common.utils.JsonUtils;
  16. import cc.iotkit.common.utils.MapstructUtils;
  17. import cc.iotkit.common.utils.UniqueIdUtil;
  18. import cc.iotkit.comp.model.DeviceState;
  19. import cc.iotkit.comp.model.RegisterInfo;
  20. import cc.iotkit.data.manager.IDeviceInfoData;
  21. import cc.iotkit.data.manager.IDeviceOtaInfoData;
  22. import cc.iotkit.data.manager.IProductData;
  23. import cc.iotkit.data.manager.IProductModelData;
  24. import cc.iotkit.model.device.DeviceInfo;
  25. import cc.iotkit.model.device.message.ThingModelMessage;
  26. import cc.iotkit.model.ota.DeviceOtaInfo;
  27. import cc.iotkit.model.product.Product;
  28. import cc.iotkit.model.product.ProductModel;
  29. import cc.iotkit.mq.MqProducer;
  30. import lombok.extern.slf4j.Slf4j;
  31. import org.apache.commons.lang3.StringUtils;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.beans.factory.annotation.Qualifier;
  34. import org.springframework.stereotype.Service;
  35. import java.util.*;
  36. @Slf4j
  37. @Service
  38. public class DeviceBehaviourService {
  39. @Autowired
  40. private IProductModelData productModelData;
  41. @Autowired
  42. private IDeviceOtaInfoData deviceOtaInfoData;
  43. @Autowired
  44. @Qualifier("deviceInfoDataCache")
  45. private IDeviceInfoData deviceInfoData;
  46. @Autowired
  47. private MqProducer<ThingModelMessage> producer;
  48. @Autowired
  49. @Qualifier("productDataCache")
  50. private IProductData productData;
  51. public void register(RegisterInfo info) {
  52. try {
  53. DeviceInfo deviceInfo = register(null, info);
  54. //子设备注册
  55. List<RegisterInfo.SubDevice> subDevices = info.getSubDevices();
  56. if (subDevices == null) {
  57. return;
  58. }
  59. for (RegisterInfo.SubDevice subDevice : subDevices) {
  60. register(deviceInfo.getDeviceId(),
  61. new RegisterInfo(subDevice.getProductKey(),
  62. subDevice.getDeviceName(),
  63. subDevice.getModel(),
  64. subDevice.getTag(), null));
  65. }
  66. } catch (BizException e) {
  67. log.error("register device error", e);
  68. throw e;
  69. } catch (Throwable e) {
  70. log.error("register device error", e);
  71. throw new BizException(ErrCode.DEVICE_REGISTER_ERROR, e);
  72. }
  73. }
  74. public DeviceInfo register(String parentId, RegisterInfo info) {
  75. String pk = info.getProductKey();
  76. String dn = info.getDeviceName();
  77. String model = info.getModel();
  78. //子设备注册处理
  79. if (parentId != null) {
  80. //透传设备:pk为空、model不为空,使用model查询产品
  81. if (StringUtils.isBlank(pk) && StringUtils.isNotBlank(model)) {
  82. ProductModel productModel = productModelData.findByModel(model);
  83. if (productModel == null) {
  84. throw new BizException(ErrCode.PRODUCT_MODEL_NOT_FOUND);
  85. }
  86. pk = productModel.getProductKey();
  87. }
  88. }
  89. Product product = productData.findByProductKey(pk);
  90. if (product == null) {
  91. throw new BizException(ErrCode.PRODUCT_NOT_FOUND);
  92. }
  93. String uid = product.getUid();
  94. DeviceInfo device = deviceInfoData.findByProductKeyAndDeviceName(pk, info.getDeviceName());
  95. boolean reportMsg = false;
  96. if (device != null) {
  97. log.info("device already registered");
  98. device.setModel(model);
  99. } else {
  100. //不存在,注册新设备
  101. device = new DeviceInfo();
  102. device.setId(DeviceUtil.newDeviceId(dn));
  103. device.setParentId(parentId);
  104. device.setUid(uid);
  105. device.setDeviceId(device.getId());
  106. device.setProductKey(pk);
  107. device.setDeviceName(dn);
  108. device.setModel(model);
  109. //默认离线
  110. device.setState(new DeviceInfo.State(false, null, null));
  111. device.setCreateAt(System.currentTimeMillis());
  112. reportMsg = true;
  113. //auth、acl
  114. }
  115. //透传设备,默认在线
  116. if (product.isTransparent()) {
  117. device.setState(new DeviceInfo.State(true, System.currentTimeMillis(), null));
  118. }
  119. if (parentId != null) {
  120. //子设备更换网关重新注册更新父级ID
  121. device.setParentId(parentId);
  122. reportMsg = true;
  123. }
  124. deviceInfoData.save(device);
  125. //新设备或更换网关需要产生注册消息
  126. if (reportMsg) {
  127. log.info("device registered:{}", JsonUtils.toJsonString(device));
  128. //新注册设备注册消息
  129. ThingModelMessage modelMessage = new ThingModelMessage(
  130. UUID.randomUUID().toString(),
  131. UniqueIdUtil.newRequestId(), "",
  132. pk, dn, uid,
  133. ThingModelMessage.TYPE_LIFETIME, "register",
  134. 0, new HashMap<>(), System.currentTimeMillis(),
  135. System.currentTimeMillis()
  136. );
  137. reportMessage(modelMessage);
  138. }
  139. return device;
  140. }
  141. public void deviceAuth(String productKey,
  142. String deviceName,
  143. String productSecret,
  144. String deviceSecret) {
  145. DeviceInfo deviceInfo = deviceInfoData.findByProductKeyAndDeviceName(productKey, deviceName);
  146. if (deviceInfo == null) {
  147. throw new BizException(ErrCode.DEVICE_NOT_FOUND);
  148. }
  149. Product product = getProductKey(productKey);
  150. if (!product.getProductSecret().equals(productSecret)) {
  151. throw new BizException(ErrCode.PRODUCT_SECRET_ERROR);
  152. }
  153. //todo 按产品ProductSecret认证,子设备需要父设备认证后可通过验证
  154. // Optional<Product> optProduct = productRepository.findById(productKey);
  155. // if (!optProduct.isPresent()) {
  156. // throw new BizException("product does not exist");
  157. // }
  158. // Product product = optProduct.get();
  159. // if (product.getNodeType()) {
  160. //
  161. // }
  162. }
  163. public boolean isOnline(String productKey,
  164. String deviceName) {
  165. DeviceInfo device = deviceInfoData.findByProductKeyAndDeviceName(productKey, deviceName);
  166. DeviceInfo deviceInfo = deviceInfoData.findByDeviceId(device.getDeviceId());
  167. return deviceInfo.getState().isOnline();
  168. }
  169. public void deviceStateChange(String productKey,
  170. String deviceName,
  171. boolean online) {
  172. DeviceInfo device = deviceInfoData.findByProductKeyAndDeviceName(productKey, deviceName);
  173. if (device == null) {
  174. log.warn("productKey: {},deviceName:{},online: {}", productKey, deviceName, online);
  175. throw new BizException(ErrCode.DEVICE_NOT_FOUND);
  176. }
  177. deviceStateChange(device, online);
  178. //父设备ID不为空说明是子设备
  179. if (device.getParentId() != null) {
  180. return;
  181. }
  182. //否则为父设备,同步透传子设备状态
  183. List<String> subDeviceIds = deviceInfoData.findSubDeviceIds(device.getDeviceId());
  184. for (String subDeviceId : subDeviceIds) {
  185. DeviceInfo subDevice = deviceInfoData.findByDeviceId(subDeviceId);
  186. Product product = productData.findByProductKey(subDevice.getProductKey());
  187. Boolean transparent = product.getTransparent();
  188. //透传设备父设备上线,子设备也上线。非透传设备父设备离线,子设备才离线
  189. if (transparent != null && transparent || !online) {
  190. deviceStateChange(subDevice, online);
  191. }
  192. }
  193. }
  194. private void deviceStateChange(DeviceInfo device, boolean online) {
  195. if (online) {
  196. device.getState().setOnline(true);
  197. device.getState().setOnlineTime(System.currentTimeMillis());
  198. } else {
  199. device.getState().setOnline(false);
  200. device.getState().setOfflineTime(System.currentTimeMillis());
  201. }
  202. deviceInfoData.save(device);
  203. //设备状态变更消息
  204. ThingModelMessage modelMessage = new ThingModelMessage(
  205. UUID.randomUUID().toString(),
  206. UniqueIdUtil.newRequestId(), "",
  207. device.getProductKey(), device.getDeviceName(), device.getUid(),
  208. ThingModelMessage.TYPE_STATE,
  209. online ? DeviceState.STATE_ONLINE : DeviceState.STATE_OFFLINE,
  210. 0,
  211. new HashMap<>(), System.currentTimeMillis(),
  212. System.currentTimeMillis()
  213. );
  214. reportMessage(modelMessage);
  215. }
  216. public void reportMessage(ThingModelMessage message) {
  217. try {
  218. DeviceInfo device = deviceInfoData.findByProductKeyAndDeviceName(
  219. message.getProductKey(), message.getDeviceName());
  220. if (device == null) {
  221. return;
  222. }
  223. message.setId(UUID.randomUUID().toString());
  224. if (message.getOccurred() == null) {
  225. message.setOccurred(System.currentTimeMillis());
  226. }
  227. if (message.getTime() == null) {
  228. message.setTime(System.currentTimeMillis());
  229. }
  230. message.setDeviceId(device.getDeviceId());
  231. producer.publish(Constants.THING_MODEL_MESSAGE_TOPIC, message);
  232. } catch (Throwable e) {
  233. log.error("send thing model message error", e);
  234. }
  235. }
  236. /**
  237. * 提供给js调用的方法
  238. */
  239. public void reportMessage(String jsonMsg) {
  240. ThingModelMessage message = JsonUtils.parseObject(jsonMsg, ThingModelMessage.class);
  241. reportMessage(message);
  242. }
  243. public void deviceOta(ThingModelMessage message) {
  244. DeviceOtaInfo deviceOtaInfoTemp = JsonUtils.objectToJavaBean(message.getData(), DeviceOtaInfo.class);
  245. if (Objects.isNull(deviceOtaInfoTemp)) {
  246. log.debug("device ota upload data is null deviceId:{}", message.getDeviceId());
  247. return;
  248. }
  249. deviceOtaInfoTemp.setTaskId(message.getMid());
  250. deviceOtaInfoTemp.setDeviceId(message.getDeviceId());
  251. deviceOtaInfoTemp.setDeviceName(message.getDeviceName());
  252. deviceOtaInfoTemp.setProductKey(message.getProductKey());
  253. DeviceOtaInfo deviceOtaInfo = deviceOtaInfoData.findOneByCondition(DeviceOtaInfo.builder()
  254. .taskId(message.getMid())
  255. .productKey(message.getProductKey())
  256. .deviceName(message.getDeviceName())
  257. .deviceId(message.getDeviceId()).build());
  258. if (Objects.nonNull(deviceOtaInfo)) {
  259. deviceOtaInfo.setStep(deviceOtaInfoTemp.getStep());
  260. } else {
  261. deviceOtaInfo = deviceOtaInfoTemp;
  262. }
  263. deviceOtaInfoData.save(deviceOtaInfo);
  264. }
  265. public Product getProductKey(String productKey) {
  266. return productData.findByProductKey(productKey);
  267. }
  268. }