-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtwinklier-api-client.ts
146 lines (123 loc) · 4.37 KB
/
twinklier-api-client.ts
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
import * as crypto from "crypto";
import axios, { AxiosRequestConfig, AxiosResponse, Method } from "axios";
import { URLSearchParams } from "url";
export enum DeviceMode {
Off = "off",
Movie = "movie",
Demo = "demo",
RealTime = "rt"
}
export class TwinklySession {
private readonly hostname: string;
private readonly baseUrl: string;
private authToken: string;
private authExpiration: number;
private constructor(hostname: string) {
this.hostname = hostname;
this.baseUrl = `http://${hostname}/xled/v1`;
this.authToken = null;
this.authExpiration = null;
}
private async connectAsync(): Promise<any> {
let challenge = crypto.randomBytes(32).toString("base64");
let response = null;
try {
response = await axios.post(`${this.baseUrl}/login`, { challenge });
}
catch (ex) {
console.log(`Login to ${this.baseUrl} failed. Error message: ${ex || ex.message}`)
throw ex;
}
if (!response.data || !response.data.authentication_token) {
debugger;
throw new Error("Login response did not included expected data.");
}
this.authToken = response.data.authentication_token;
this.authExpiration = (new Date().getTime() + response.data.authentication_token_expires_in * 1000) - 10000;
return this.postAsync("verify");
}
private requestAsync(method: Method, path: string, data?: any, type?: string) : Promise<AxiosResponse> {
let config: AxiosRequestConfig = {
url: `${this.baseUrl}/${path}`,
method: method,
data: data,
headers: {
"X-Auth-Token": this.authToken,
"Content-Type": type || "application/json"
}
};
return axios(config);
}
private postAsync(path: string, data?: any, type?: string): Promise<AxiosResponse> {
return this.requestAsync("POST", path, data, type);
}
private fetchAsync(path: string): Promise<AxiosResponse> {
return this.requestAsync("GET", path);
}
static connectToHost(hostname: string) : Promise<TwinklySession> {
let session = new TwinklySession(hostname);
return session.connectAsync().then(() => { return session; });
}
setModeAsync(mode: DeviceMode): Promise<any> {
return this.postAsync("led/mode", { mode });
}
async uploadMovie(movie: Movie) {
await this.setModeAsync(DeviceMode.Off);
await this.postAsync("led/movie/full", movie.getMovieBuffer(), "application/octet-stream");
return this.postAsync("led/movie/config", {
leds_number: movie.ledCount,
frames_number: movie.frames.length,
frame_delay: movie.frameDelay
});
}
}
export interface MoviePixel {
r: number;
g: number;
b: number;
}
export class MovieFrame {
ledCount: number;
private _pixels : Array<MoviePixel>;
constructor(ledCount: number) {
this.ledCount = ledCount;
this._pixels = new Array<MoviePixel>(this.ledCount);
this.fill({ r: 0, b: 0, g: 0 });
}
get pixels() : Array<MoviePixel> {
return this._pixels;
}
fill(color: MoviePixel) {
for (let i = 0; i < this._pixels.length; i++) {
this._pixels[i] = { ...color };
}
}
getUint8Buffer(): Uint8Array {
let buffer = new Uint8Array(this.pixels.length * 3);
for (let i = 0, bufferIndex = 0; i < this.pixels.length; i++) {
const pixel = this.pixels[i];
buffer[bufferIndex++] = pixel.r;
buffer[bufferIndex++] = pixel.g;
buffer[bufferIndex++] = pixel.b;
}
return buffer;
}
}
export class Movie {
frameDelay: number;
ledCount: number;
frames: Array<MovieFrame>;
constructor(ledCount: number, frameDelay: number, frames?: Array<MovieFrame>) {
this.ledCount = ledCount;
this.frameDelay = frameDelay;
this.frames = frames || new Array<MovieFrame>();
}
getMovieBuffer(): Uint8Array {
const pixelsPerFrame = this.ledCount * 3;
let buffer = new Uint8Array(pixelsPerFrame * this.frames.length);
for (let i = 0; i < this.frames.length; i++) {
buffer.set(this.frames[i].getUint8Buffer(), i * pixelsPerFrame);
}
return buffer;
}
}