Mqtt.ets 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { MqttAsync, MqttClient, MqttClientOptions, MqttConnectOptions,MqttQos, MqttMessage, MqttPublishOptions } from '@ohos/mqtt';
  2. import CommonConstants from '../../Common/constants/CommonConstants';
  3. import AntiWristStrap from '../../viewmodel/device/AntiWristStrap';
  4. import CardReader from '../../viewmodel/device/CardReader';
  5. import ElectricScrewdriver from '../../viewmodel/device/ElectricScrewdriver';
  6. import ElectricSolderingIron from '../../viewmodel/device/ElectricSolderingIron';
  7. import Lighting from '../../viewmodel/device/Lighting';
  8. import TempHumiditySensor from '../../viewmodel/device/TempHumiditySensor';
  9. import ThreeColourLight from '../../viewmodel/device/ThreeColourLight';
  10. import WeldFumeExtractor from '../../viewmodel/device/WeldFumeExtractor';
  11. import BusinessConstant, { DeviceType } from '../constants/CommonConstants'
  12. const TAG = 'hhtest';
  13. type MessageCallback = (topic: string, payload: string) => void;
  14. interface TagValuePair {
  15. tag: string;
  16. value: number;
  17. }
  18. class MqttManager {
  19. // static readonly MQTT_SERVICE = '192.168.1.10'
  20. private static instance: MqttManager;
  21. private client: MqttClient | null = null;
  22. private callbacks: Map<string, MessageCallback[]> = new Map();
  23. private constructor() {}
  24. public static getInstance(): MqttManager {
  25. if (!MqttManager.instance) {
  26. MqttManager.instance = new MqttManager();
  27. }
  28. return MqttManager.instance;
  29. }
  30. public init(options: MqttClientOptions): void {
  31. try {
  32. this.client = MqttAsync.createMqtt(options);
  33. this.registerCallbacks();
  34. console.info(TAG, 'MQTT client initialized');
  35. } catch (err) {
  36. console.error(TAG, `Initialization failed: ${JSON.stringify(err)}`);
  37. }
  38. }
  39. private registerCallbacks(): void {
  40. if (!this.client) return;
  41. this.client.messageArrived((err, message) => {
  42. if (err) {
  43. console.error(TAG, `Message error: ${err.message}`);
  44. return;
  45. }
  46. this.handleMessage(message);
  47. });
  48. this.client.connectLost((err) => {
  49. if (err) {
  50. console.error(TAG, `Connection lost: ${err.message}`);
  51. }
  52. this.reconnect();
  53. });
  54. }
  55. // 修改后的 handleMessage 方法片段
  56. private handleMessage(message: MqttMessage): void {
  57. const topic = message.topic;
  58. const payload = message.payload.toString();
  59. const topicCallbacks = this.callbacks.get(topic) || [];
  60. topicCallbacks.forEach(cb => cb(topic, payload));
  61. try {
  62. const valueJson: MQTTReceiveData = JSON.parse(payload);
  63. //订阅主题一的接收数据
  64. if (CommonConstants.mqttSubscribeTopic1 == topic) {
  65. let device0: ThreeColourLight = {
  66. LedRed: 0,
  67. LedOrange: 0,
  68. LedGreen: 0,
  69. Buzzer: 0,
  70. OpenStatus: 0
  71. }
  72. let device1: WeldFumeExtractor = { ExhaustFan: 0, OnlineStatus: 0 }
  73. let device2: ElectricSolderingIron = { SolderingCurrTemp: 0, OnlineStatus: 0 }
  74. let device3: ElectricScrewdriver = {
  75. TighteRotationDirection: 0,
  76. TorqueHoldTime: 0,
  77. TightenTorqueTarget: 0,
  78. TorqueUpperLimit: 0,
  79. TorqueLowerLimit: 0,
  80. EnableFloatSlipDetection: 0,
  81. FloatDetectionTurns: 0,
  82. OnlineStatus: 0
  83. }
  84. let device4: AntiWristStrap = { RingWearNormal: 0, RingWearStandby: 0, RingWearFault: 0, OnlineStatus: 0 }
  85. let device5: CardReader = { RfidCardNum1: '', RfidCardNum2: '', OnlineStatus: 0 }
  86. let device6: Lighting = { lighting: 0, OnlineStatus: 0 }
  87. let device7: TempHumiditySensor = { Temperature: 0, Humidity: 0, OnlineStatus: 0 }
  88. for (const element of valueJson.d) {
  89. if (BusinessConstant.attrMap.has(element.tag)) {
  90. let deviceType: string = BusinessConstant.attrMap.get(element.tag) ?? '';
  91. switch (deviceType) {
  92. case DeviceType.ThreeColourLight:
  93. if (element.tag! === 'LedRed') {
  94. device0.LedRed = element.value
  95. } else if (element.tag! === 'LedOrange') {
  96. device0.LedOrange = element.value
  97. } else if (element.tag! === 'LedGreen') {
  98. device0.LedGreen = element.value
  99. } else if (element.tag! === 'Buzzer') {
  100. device0.Buzzer = element.value
  101. }
  102. if (device0.LedRed! === 1 || device0.LedOrange! === 1
  103. || device0.LedGreen! === 1 || device0.Buzzer! === 1) {
  104. device0.OpenStatus = 1
  105. }
  106. device0.OnlineStatus = 1
  107. break;
  108. case DeviceType.WeldFumeExtractor:
  109. if (element.tag! === 'ExhaustFan') {
  110. device1.ExhaustFan = element.value
  111. }
  112. device1.OnlineStatus = 1
  113. break;
  114. case DeviceType.ElectricSolderingIron:
  115. if (element.tag! === 'SolderingCurrTemp') {
  116. device2.SolderingCurrTemp = element.value
  117. }
  118. device2.OnlineStatus = 1
  119. break;
  120. case DeviceType.ElectricScrewdriver:
  121. if (element.tag! === 'TightenTorqueTarget') {
  122. device3.TightenTorqueTarget = element.value
  123. } else if (element.tag! === 'TorqueHoldTime') {
  124. device3.TorqueHoldTime = element.value
  125. }
  126. device3.OnlineStatus = 1
  127. break;
  128. case DeviceType.AntiWristStrap:
  129. if (element.tag! === 'RingWearNormal') {
  130. device4.RingWearNormal = element.value
  131. } else if (element.tag! === 'RingWearStandby') {
  132. device4.RingWearStandby = element.value
  133. } else if (element.tag! === 'RingWearFault') {
  134. device4.RingWearFault = element.value
  135. }
  136. device4.OnlineStatus = 1
  137. break;
  138. case DeviceType.CardReader:
  139. if (element.tag! === 'RfidCardNum1') {
  140. let value = element.value?.toString(16)
  141. device5.RfidCardNum1 = value === '0' ? '' : value
  142. } else if (element.tag! === 'RfidCardNum2') {
  143. let value = element.value?.toString(16)
  144. device5.RfidCardNum2 = value === '0' ? '' : value
  145. }
  146. device5.OnlineStatus = 1
  147. break;
  148. case DeviceType.Lighting:
  149. if (element.tag! === 'lighting') {
  150. device6.lighting = element.value
  151. }
  152. device6.OnlineStatus = 1
  153. break;
  154. case DeviceType.TempHumiditySensor:
  155. if (element.tag! === 'Temperature') {
  156. device7.Temperature = element.value
  157. } else if (element.tag! === 'Humidity') {
  158. device7.Humidity = element.value
  159. }
  160. device7.OnlineStatus = 1
  161. break;
  162. }
  163. }
  164. AppStorage.setOrCreate<ThreeColourLight>('ThreeColourLight', device0);
  165. AppStorage.setOrCreate<WeldFumeExtractor>('WeldFumeExtractor', device1);
  166. AppStorage.setOrCreate<ElectricSolderingIron>('ElectricSolderingIron', device2);
  167. AppStorage.setOrCreate<ElectricScrewdriver>('ElectricScrewdriver', device3);
  168. AppStorage.setOrCreate<AntiWristStrap>('AntiWristStrap', device4);
  169. AppStorage.setOrCreate<CardReader>('CardReader', device5);
  170. AppStorage.setOrCreate<Lighting>('Lighting', device6)
  171. AppStorage.setOrCreate<TempHumiditySensor>('TempHumiditySensor', device7)
  172. }
  173. } else if (CommonConstants.mqttSubscribeTopic2 == topic) {
  174. //订阅主题二的接收数据
  175. let device0: TempHumiditySensor = { Temperature: 0, Humidity: 0, OnlineStatus: 0 }
  176. for (const element of valueJson.d) {
  177. if (CommonConstants.attrMap.has(element.tag)) {
  178. let deviceType: string = CommonConstants.attrMap.get(element.tag) ?? '';
  179. switch (deviceType) {
  180. case DeviceType.TempHumiditySensor:
  181. if (element.tag! === 'Temperature') {
  182. device0.Temperature = element.value
  183. } else if (element.tag! === 'Humidity') {
  184. device0.Humidity = element.value
  185. }
  186. device0.OnlineStatus = 1
  187. break;
  188. }
  189. }
  190. }
  191. AppStorage.setOrCreate<TempHumiditySensor>('TempHumiditySensor', device0);
  192. }
  193. //订阅主题二的接收数据
  194. else if(CommonConstants.mqttSubscribeTopic3 == topic){
  195. const station1Set = valueJson?.d?.find(item => item.tag === 'Station1Set')?.value;
  196. const station1Weight = decodeWeight(valueJson?.d?.find(item => item.tag === 'Station1Weight')?.value);
  197. const rfidStringIn = decodeRfidString(
  198. valueJson?.d?.find(item => item.tag === 'Barcode1Data1')?.value as number,
  199. valueJson?.d?.find(item => item.tag === 'Barcode1Data2')?.value as number,
  200. valueJson?.d?.find(item => item.tag === 'Barcode1Data3')?.value as number,
  201. valueJson?.d?.find(item => item.tag === 'Barcode1Data4')?.value as number
  202. );
  203. AppStorage.SetOrCreate<number>('drawerPositionStatus', station1Set);
  204. AppStorage.SetOrCreate<number>('materialBoxWeight', station1Weight);
  205. AppStorage.SetOrCreate<string>('materialBoxInRfid', rfidStringIn);
  206. }
  207. } catch (e) {
  208. console.error("MQTT消息处理异常:", e);
  209. }
  210. }
  211. public async connect(options: MqttConnectOptions): Promise<boolean> {
  212. if (!this.client) return false;
  213. try {
  214. const res = await this.client.connect(options);
  215. if (res.code === 0) {
  216. console.info(TAG, 'Connected to broker');
  217. return true;
  218. }
  219. console.error(TAG, `Connect failed: ${res.message}`);
  220. return false;
  221. } catch (err) {
  222. console.error(TAG, `Connect error: ${err.message}`);
  223. return false;
  224. }
  225. }
  226. public async subscribe(topic: string, callback?: MessageCallback): Promise<void> {
  227. if (!this.client) return;
  228. try {
  229. const res = await this.client.subscribe({ topic, qos: 1 });
  230. if (res.code === 0) {
  231. console.info(TAG, `Subscribed to ${topic}`);
  232. if (callback) {
  233. this.addCallback(topic, callback);
  234. }
  235. }
  236. } catch (err) {
  237. console.error(TAG, `Subscribe error: ${err.message}`);
  238. }
  239. }
  240. private addCallback(topic: string, callback: MessageCallback): void {
  241. const callbacks = this.callbacks.get(topic) || [];
  242. callbacks.push(callback);
  243. this.callbacks.set(topic, callbacks);
  244. }
  245. private reconnect(): void {
  246. setTimeout(() => {
  247. this.client?.reconnect().then(success => {
  248. if (success) {
  249. console.info(TAG, 'Reconnected successfully');
  250. }
  251. });
  252. }, 5000);
  253. }
  254. public async disconnect(): Promise<void> {
  255. if (!this.client) return;
  256. try {
  257. await this.client.disconnect();
  258. console.info(TAG, 'Disconnected');
  259. } catch (err) {
  260. console.error(TAG, `Disconnect error: ${err.message}`);
  261. }
  262. }
  263. public async publish(
  264. topic: string,
  265. payload: string | object,
  266. qos: MqttQos = 1,
  267. retained: boolean = false
  268. ): Promise<void> {
  269. if (!this.client) {
  270. console.error(TAG, 'MQTT客户端未初始化');
  271. return;
  272. }
  273. try {
  274. // 统一处理 payload 类型
  275. const payloadStr = typeof payload === 'string' ? payload : JSON.stringify(payload);
  276. const options: MqttPublishOptions = {
  277. topic: topic,
  278. payload: payloadStr,
  279. qos: qos,
  280. retained: retained
  281. };
  282. const res = await this.client.publish(options);
  283. if (res.code === 0) {
  284. console.info(TAG, `消息发布成功: ${topic}`);
  285. } else {
  286. console.error(TAG, `发布失败: ${res.message}`);
  287. }
  288. } catch (err) {
  289. console.error(TAG, `发布异常: ${JSON.stringify(err)}`);
  290. }
  291. }
  292. }
  293. export default MqttManager.getInstance();
  294. export interface MQTTPublishData {
  295. w: TagValuePair[];
  296. }
  297. export interface MQTTReceiveData {
  298. d: TagValuePair[];
  299. }
  300. function decodeRegister(regValue: number | undefined): string {
  301. if (regValue === undefined || regValue === 0) return '';
  302. //if (regValue === undefined) return ''; // 处理undefined
  303. // 确保是16位无符号整数
  304. const value = regValue & 0xFFFF;
  305. // 提取高8位和低8位
  306. const highByte = (value >> 8) & 0xFF;
  307. const lowByte = value & 0xFF;
  308. // 转换为ASCII字符
  309. return String.fromCharCode(highByte) + String.fromCharCode(lowByte);
  310. }
  311. // 完整RFID解码函数
  312. function decodeRfidString(
  313. rfidData1?: number,
  314. rfidData2?: number,
  315. rfidData3?: number,
  316. rfidData4?: number
  317. ): string {
  318. return [
  319. decodeRegister(rfidData1),
  320. decodeRegister(rfidData2),
  321. decodeRegister(rfidData3),
  322. decodeRegister(rfidData4)
  323. ].join('');
  324. }
  325. function decodeWeight(regValue: number | undefined): number {
  326. if (regValue === undefined) return 0; // 处理undefined
  327. // 确保是16位无符号整数
  328. const value = regValue & 0xFFFF;
  329. // 提取高8位和低8位
  330. const highByte = (value >> 8) & 0xFF;
  331. const lowByte = value & 0xFF;
  332. // 转换为ASCII字符
  333. return highByte+lowByte/100
  334. }