elero-usb-transmitter-client 1.0.6 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ name: Node.js CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ build:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ node-version: [18.x, 20.x, 22.x]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v3
20
+ - name: Use Node.js ${{ matrix.node-version }}
21
+ uses: actions/setup-node@v3
22
+ with:
23
+ node-version: ${{ matrix.node-version }}
24
+ cache: 'npm'
25
+ - run: npm ci
26
+ - run: npm run build
27
+ - run: npm test
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # elero-usb-transmitter-client
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/elero-usb-transmitter-client.svg?style=flat-square)](https://www.npmjs.com/package/elero-usb-transmitter-client)
4
- [![build status](https://img.shields.io/travis/marc2016/elero-usb-transmitter-client/master.svg?style=flat-square)](https://travis-ci.org/github/marc2016/elero-usb-transmitter-client)
4
+ [![Node.js CI](https://github.com/marc2016/elero-usb-transmitter-client/actions/workflows/nodejs.yml/badge.svg)](https://github.com/marc2016/elero-usb-transmitter-client/actions/workflows/nodejs.yml)
5
+
5
6
 
6
7
  Elero USB Transmitter Client for node.js to send commands to Elero USB Stick and receive information. This libaray needs Elero Transmitter Stick (https://www.der-sonnenschutz-shop.de/elero-221250001-centero-transmitter-stick.html).
7
8
 
@@ -18,6 +19,30 @@ Using npm:
18
19
  $ npm install elero-usb-transmitter-client
19
20
  ```
20
21
 
22
+ ## CLI Usage
23
+
24
+ You can use the interactive CLI to control the transmitter directly.
25
+
26
+ ### Installation
27
+
28
+ **Globally (if published to npm):**
29
+ ```bash
30
+ npm install -g elero-usb-transmitter-client
31
+ elero-cli
32
+ ```
33
+
34
+ **Via npx (if published to npm):**
35
+ ```bash
36
+ npx elero-usb-transmitter-client
37
+ ```
38
+
39
+ **From Source (Development):**
40
+ 1. Clone the repository
41
+ 2. Install dependencies: `npm install`
42
+ 3. Build the project: `npm run build`
43
+ 4. Link command: `npm link`
44
+ 5. Run: `elero-cli`
45
+
21
46
  ## Example
22
47
 
23
48
  ### Initialize
@@ -57,6 +82,42 @@ console.log(response)
57
82
  await client.close()
58
83
  ```
59
84
 
85
+ ## Changelog
86
+
87
+ ### 1.1.2
88
+
89
+ - Fix CLI entry point name in `package.json`
90
+
91
+ ### 1.1.1
92
+
93
+ - Fixed `responseBytes are null` error by handling fragmented serial packets
94
+ - Added detailed unit tests with mocks
95
+
96
+ ### 1.1.0
97
+
98
+ - Added interactive CLI (`elero-cli`)
99
+ - Added `inquirer` and `commander` dependencies
100
+
101
+ ### 1.0.6
102
+
103
+ - Updated `serialport` dependency
104
+ - Fixed errors in response handling
105
+
106
+ ### 1.0.5
107
+
108
+ - Improved mutex handling (release added)
109
+
110
+ ### 1.0.4
111
+
112
+ - Fixed promise rejection logic
113
+ - Added null checks for response bytes
114
+
115
+ ### 1.0.0
116
+
117
+ - Initial release with `getInfo`, `sendControlCommand`, and `checkChannels`
118
+ - Implemented `UsbTransmitterClient`
119
+
120
+
60
121
  ## License
61
122
 
62
123
  [MIT](LICENSE)
@@ -0,0 +1,18 @@
1
+ import { SerialPort } from 'serialport';
2
+ import { Response } from './model/Response';
3
+ import { ControlCommand } from './domain/enums';
4
+ export declare class UsbTransmitterClient {
5
+ serialPort: SerialPort<any>;
6
+ constructor(devPath: string);
7
+ open(): Promise<void>;
8
+ close(): Promise<void>;
9
+ checkChannels(): Promise<number[]>;
10
+ getInfo(channel: number): Promise<Response>;
11
+ sendControlCommand(channel: number, controlCommand: ControlCommand): Promise<Response>;
12
+ private waitForResponse;
13
+ private sendCommand;
14
+ private readResponseBytes;
15
+ private calculateChecksum;
16
+ private getActiveChannels;
17
+ private parseResponse;
18
+ }
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.UsbTransmitterClient = void 0;
40
+ var serialport_1 = require("serialport");
41
+ var _ = require("lodash");
42
+ var constants_1 = require("./domain/constants");
43
+ var enums_1 = require("./domain/enums");
44
+ var async_mutex_1 = require("async-mutex");
45
+ var DEFAULT_BAUDRATE = 38400;
46
+ var DEFAULT_BYTESIZE = 8;
47
+ var DEFAULT_PARITY = 'none';
48
+ var DEFAULT_STOPBITS = 1;
49
+ var mutex = new async_mutex_1.Mutex();
50
+ var UsbTransmitterClient = /** @class */ (function () {
51
+ function UsbTransmitterClient(devPath) {
52
+ this.serialPort = new serialport_1.SerialPort({
53
+ path: devPath,
54
+ baudRate: DEFAULT_BAUDRATE,
55
+ dataBits: DEFAULT_BYTESIZE,
56
+ parity: DEFAULT_PARITY,
57
+ stopBits: DEFAULT_STOPBITS,
58
+ autoOpen: false,
59
+ });
60
+ }
61
+ UsbTransmitterClient.prototype.open = function () {
62
+ var _this = this;
63
+ return new Promise(function (resolve, reject) {
64
+ if (!_this.serialPort.isOpen) {
65
+ _this.serialPort.open(function (error) {
66
+ if (error)
67
+ reject(error);
68
+ _this.serialPort.flush(function (error) {
69
+ if (error)
70
+ reject(error);
71
+ resolve();
72
+ });
73
+ });
74
+ }
75
+ });
76
+ };
77
+ UsbTransmitterClient.prototype.close = function () {
78
+ var _this = this;
79
+ return new Promise(function (resolve, reject) {
80
+ _this.serialPort.close(function (error) {
81
+ if (error)
82
+ reject(error);
83
+ resolve();
84
+ });
85
+ });
86
+ };
87
+ UsbTransmitterClient.prototype.checkChannels = function () {
88
+ return __awaiter(this, void 0, void 0, function () {
89
+ var data, release, responseBytes, response;
90
+ return __generator(this, function (_a) {
91
+ switch (_a.label) {
92
+ case 0:
93
+ data = [constants_1.BYTE_HEADER, constants_1.BYTE_LENGTH_2, enums_1.EasyCommand.EASY_CHECK];
94
+ return [4 /*yield*/, mutex.acquire()];
95
+ case 1:
96
+ release = _a.sent();
97
+ _a.label = 2;
98
+ case 2:
99
+ _a.trys.push([2, , 5, 6]);
100
+ return [4 /*yield*/, this.sendCommand(data)];
101
+ case 3:
102
+ _a.sent();
103
+ return [4 /*yield*/, this.waitForResponse(constants_1.RESPONSE_LENGTH_CHECK)];
104
+ case 4:
105
+ responseBytes = _a.sent();
106
+ response = this.parseResponse(responseBytes);
107
+ return [2 /*return*/, response.activeChannels];
108
+ case 5:
109
+ release();
110
+ return [7 /*endfinally*/];
111
+ case 6: return [2 /*return*/];
112
+ }
113
+ });
114
+ });
115
+ };
116
+ UsbTransmitterClient.prototype.getInfo = function (channel) {
117
+ return __awaiter(this, void 0, void 0, function () {
118
+ var lowChannels, highChannels, data, release, responseBytes, response;
119
+ return __generator(this, function (_a) {
120
+ switch (_a.label) {
121
+ case 0:
122
+ lowChannels = (1 << (channel - 1)) & 0xff;
123
+ highChannels = (1 << (channel - 1)) >> 8;
124
+ data = [
125
+ constants_1.BYTE_HEADER,
126
+ constants_1.BYTE_LENGTH_4,
127
+ enums_1.EasyCommand.EASY_INFO,
128
+ highChannels,
129
+ lowChannels,
130
+ ];
131
+ return [4 /*yield*/, mutex.acquire()];
132
+ case 1:
133
+ release = _a.sent();
134
+ _a.label = 2;
135
+ case 2:
136
+ _a.trys.push([2, , 5, 6]);
137
+ return [4 /*yield*/, this.sendCommand(data)];
138
+ case 3:
139
+ _a.sent();
140
+ return [4 /*yield*/, this.waitForResponse(constants_1.RESPONSE_LENGTH_INFO)];
141
+ case 4:
142
+ responseBytes = _a.sent();
143
+ response = this.parseResponse(responseBytes);
144
+ return [2 /*return*/, response];
145
+ case 5:
146
+ release();
147
+ return [7 /*endfinally*/];
148
+ case 6: return [2 /*return*/];
149
+ }
150
+ });
151
+ });
152
+ };
153
+ UsbTransmitterClient.prototype.sendControlCommand = function (channel, controlCommand) {
154
+ return __awaiter(this, void 0, void 0, function () {
155
+ var lowChannels, highChannels, data, release, responseBytes, response;
156
+ return __generator(this, function (_a) {
157
+ switch (_a.label) {
158
+ case 0:
159
+ lowChannels = (1 << (channel - 1)) & 0xff;
160
+ highChannels = (1 << (channel - 1)) >> 8;
161
+ data = [
162
+ constants_1.BYTE_HEADER,
163
+ constants_1.BYTE_LENGTH_5,
164
+ enums_1.EasyCommand.EASY_SEND,
165
+ highChannels,
166
+ lowChannels,
167
+ controlCommand,
168
+ ];
169
+ return [4 /*yield*/, mutex.acquire()];
170
+ case 1:
171
+ release = _a.sent();
172
+ _a.label = 2;
173
+ case 2:
174
+ _a.trys.push([2, , 5, 6]);
175
+ return [4 /*yield*/, this.sendCommand(data)];
176
+ case 3:
177
+ _a.sent();
178
+ return [4 /*yield*/, this.waitForResponse(constants_1.RESPONSE_LENGTH_INFO)];
179
+ case 4:
180
+ responseBytes = _a.sent();
181
+ response = this.parseResponse(responseBytes);
182
+ return [2 /*return*/, response];
183
+ case 5:
184
+ release();
185
+ return [7 /*endfinally*/];
186
+ case 6: return [2 /*return*/];
187
+ }
188
+ });
189
+ });
190
+ };
191
+ UsbTransmitterClient.prototype.waitForResponse = function (length) {
192
+ var _this = this;
193
+ return new Promise(function (resolve, reject) {
194
+ var timeout = setTimeout(function () {
195
+ cleanup();
196
+ reject(new Error('Timeout waiting for response'));
197
+ }, 2000);
198
+ var tryRead = function () {
199
+ var buffer = _this.serialPort.read(length);
200
+ if (buffer) {
201
+ cleanup();
202
+ resolve(buffer);
203
+ }
204
+ };
205
+ var cleanup = function () {
206
+ clearTimeout(timeout);
207
+ _this.serialPort.removeListener('readable', tryRead);
208
+ };
209
+ _this.serialPort.on('readable', tryRead);
210
+ tryRead();
211
+ });
212
+ };
213
+ UsbTransmitterClient.prototype.sendCommand = function (data) {
214
+ var _this = this;
215
+ var checksum = this.calculateChecksum(data);
216
+ data.push(checksum);
217
+ return new Promise(function (resolve, reject) {
218
+ _this.serialPort.flush(function (error) {
219
+ if (error)
220
+ reject(error);
221
+ _this.serialPort.write(data, function (error) {
222
+ if (error)
223
+ reject(error);
224
+ resolve(data.length);
225
+ });
226
+ });
227
+ });
228
+ };
229
+ UsbTransmitterClient.prototype.readResponseBytes = function (length) {
230
+ //Get the serial data from the serial port.
231
+ var response = this.serialPort.read(length);
232
+ return response;
233
+ };
234
+ UsbTransmitterClient.prototype.calculateChecksum = function (data) {
235
+ //Calculate checksum.
236
+ //All the sum of all bytes (Header to CS) must be 0x00.
237
+ var sum = _.sum(data);
238
+ var result = (256 - sum) % 256;
239
+ return result;
240
+ };
241
+ UsbTransmitterClient.prototype.getActiveChannels = function (byte, start) {
242
+ var channels = new Array();
243
+ for (var i = 0; i < 9; i++) {
244
+ if (((byte >> i) & 1) == 1) {
245
+ var channel = i + start;
246
+ channels.push(channel);
247
+ }
248
+ }
249
+ return channels;
250
+ };
251
+ UsbTransmitterClient.prototype.parseResponse = function (bytes) {
252
+ var activeHighChannels = this.getActiveChannels(bytes[3], 9);
253
+ var activeLowChannels = this.getActiveChannels(bytes[4], 1);
254
+ var activeChannels = _.concat(activeLowChannels, activeHighChannels);
255
+ var response = {
256
+ header: bytes[0],
257
+ length: bytes[1],
258
+ command: bytes[2],
259
+ activeChannels: activeChannels,
260
+ checksum: -1,
261
+ status: null,
262
+ statusCode: -1,
263
+ };
264
+ if (bytes.length == constants_1.RESPONSE_LENGTH_CHECK) {
265
+ response.checksum = bytes[5];
266
+ //Easy Ack (the answer on Easy Info)
267
+ }
268
+ else if (bytes.length == constants_1.RESPONSE_LENGTH_SEND) {
269
+ if (bytes[5] in enums_1.InfoData) {
270
+ response.status = bytes[5];
271
+ }
272
+ else {
273
+ response.status = enums_1.InfoData.INFO_UNKNOWN;
274
+ }
275
+ response.checksum = bytes[6];
276
+ }
277
+ else {
278
+ response.status = enums_1.InfoData.INFO_UNKNOWN;
279
+ }
280
+ return response;
281
+ };
282
+ return UsbTransmitterClient;
283
+ }());
284
+ exports.UsbTransmitterClient = UsbTransmitterClient;
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};