1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166 | 3x
3x
3x
3x
3x
3x
3x
3x
4x
4x
4x
4x
4x
4x
4x
4x
4x
4x
4x
4x
4x
4x
3x
2x
2x
2x
2x
3x
2x
2x
2x
2x
2x
3x
2x
2x
2x
3x
2x
2x
2x
2x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
1x
1x
1x
1x
3x
1x
1x
1x
1x
| import { Command } from './command';
import { PBResponseBuffer } from './comms'
import { Buffer } from 'buffer/'
/*
Constants
*/
/// Control Service UUID string
export const ControlService = 'FDC1';
/// Control Characteristic UUID string
export const ControlCharacteristic = 'cafe1001-c0ff-ee01-8000-a110ca7ab1e0';
/// The max value a shade accepts for position.
export const PositionMaxValue = 10000;
/// The max value a shade accepts for tilt
export const TiltMaxValue = 100;
/// The max value a shade accepts for velocity
export const VelocityMaxValue = 160;
/**
All values are between 0-1. This value represents the percentage of light that the shade is allowing in.
i.e.
1 is a fully open shade (100% light allowed)
0 is a fully closed shade (0% light allowed)
*/
export interface GoToPositionOptions {
/**
* Servo 1 Position (0 - 1) (0% - 100% light)
*/
servo1?: number; // test doc
/**
* Servo 2 Position (0 - 1) (0% - 100% light)
*/
servo2?: number;
/**
* Servo 3 Position (0 - 1) (0% - 100% light)
*/
servo3?: number;
/**
* Tilt Position (0 - 1) (0% - 100% light)
*/
tilt?: number;
/**
* Velocity for command (0 - 1) (0% - 100% velocity)
*/
velocity?: number;
}
/**
* GoToPositionCommand
*/
export class GoToPositionCommand extends Command<PBResponseBuffer> {
constructor(options: GoToPositionOptions) {
super(ControlService, ControlCharacteristic, (encoder) => {
const servo1 = options.servo1 === undefined ? 0x8000 : (options.servo1 * PositionMaxValue);
const servo2 = options.servo2 === undefined ? 0x8000 : (options.servo2 * PositionMaxValue);
const servo3 = options.servo3 === undefined ? 0x8000 : (options.servo3 * PositionMaxValue);
const tilt = options.tilt === undefined ? 0x8000 : (options.tilt * TiltMaxValue);
const velocity = options.velocity === undefined ? 0x00 : (options.velocity * VelocityMaxValue);
encoder.setHeader(0xF1, 0x01);
encoder.addUInt16(servo1);
encoder.addUInt16(servo2);
encoder.addUInt16(servo3);
encoder.addUInt16(tilt);
encoder.addUInt8(velocity);
});
this.name = "GoToPosition";
}
parseResponse = (buffer: Buffer) : PBResponseBuffer => {
return new PBResponseBuffer(buffer);
}
}
/** Simple connect test with no shade motion or changes to shade. - If the LED is enabled, it illuminates on connect. */
export class PingCommand extends Command<PBResponseBuffer> {
constructor() {
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF7, 0x00);
});
this.name = "Ping";
}
parseResponse = (buffer: Buffer) : PBResponseBuffer => {
return new PBResponseBuffer(buffer);
}
}
/** Jog the shade slightly for visual identification */
export class JogCommand extends Command<PBResponseBuffer> {
/// items: number of times to jog the shade
constructor(times: number = 0x03) {
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF7, 0x11);
encoder.addUInt8(times);
});
this.name = "Jog";
}
parseResponse = (buffer: Buffer) : PBResponseBuffer => {
return new PBResponseBuffer(buffer);
}
}
/// TODO: DOCUMENT
export class WakeCommand extends Command<PBResponseBuffer> {
constructor() {
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF3, 0xB5);
});
this.name = "Wake";
}
}
/// Immediately halt movement
export class StopCommand extends Command<PBResponseBuffer> {
constructor() {
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF7, 0xB8);
});
this.name = "Stop";
}
parseResponse = (buffer: Buffer) : PBResponseBuffer => {
return new PBResponseBuffer(buffer);
}
}
/// Reserved scenes are common across all shades. i.e. double click open means go to top limit, open means go to top offset etc etc.
export enum ReservedScene {
doubleClickOpen = 0xA201,
open = 0xA202,
close = 0xA203,
doubleClickClose = 0xA204,
tiltOpen = 0xA205,
tiltClose = 0xA206,
doubleTiltOpen = 0xA207,
doubleTileClose = 0xA208,
heart = 0xA20A,
doubleHeart = 0x20B
}
/// Move the shade to a reserved scene position
export class GoToReservedSceneCommand extends Command<PBResponseBuffer> {
constructor(scene: ReservedScene) {
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF7, 0xBA);
encoder.addUInt16(scene);
});
this.name = "GoToReservedScene";
}
}
// Activate a scene on a single shade. In the next layer up, this should be "ActivateScene" with a scene ID,
// & use scene members persistence to identify target shades.
export class GoToSceneCommand extends Command<PBResponseBuffer> {
constructor(scene: number){
super(ControlService, ControlCharacteristic, (encoder) => {
encoder.setHeader(0xF7, 0xBA);
encoder.addUInt16(scene);
});
this.name = "GoToScene";
}
}
|