@robotical/webapp-types 3.25.5 → 3.25.7
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.
- package/dist-types/package.json +1 -1
- package/dist-types/src/application/RAFTs/Marty/PublishedDataAnalyser.d.ts +2 -2
- package/dist-types/src/application/RAFTs/Marty/PublishedDataAnalyser.js +7 -23
- package/dist-types/src/components/oneoffs/calibration-screens/ColourSensorCalibration/messages.d.ts +17 -13
- package/dist-types/src/components/oneoffs/calibration-screens/ColourSensorCalibration/messages.js +17 -13
- package/dist-types/src/screens/configuration/marty/Diagnostics/ColourSensorDiagnostics/messages.d.ts +2 -0
- package/dist-types/src/screens/configuration/marty/Diagnostics/ColourSensorDiagnostics/messages.js +3 -1
- package/dist-types/src/utils/colour-calibration-reconnect.d.ts +19 -0
- package/dist-types/src/utils/colour-calibration-reconnect.js +261 -0
- package/dist-types/src/utils/colour-calibration-records.d.ts +21 -0
- package/dist-types/src/utils/colour-calibration-records.js +253 -0
- package/dist-types/src/utils/colour-classifier.d.ts +32 -0
- package/dist-types/src/utils/colour-classifier.js +37 -0
- package/dist-types/src/utils/colour-sensor-diagnostics.d.ts +162 -0
- package/dist-types/src/utils/colour-sensor-diagnostics.js +364 -0
- package/dist-types/src/utils/colour-sensor-operation.d.ts +2 -0
- package/dist-types/src/utils/colour-sensor-operation.js +62 -0
- package/dist-types/src/utils/colour-sensor-profile.d.ts +32 -0
- package/dist-types/src/utils/colour-sensor-profile.js +229 -0
- package/dist-types/src/utils/colour-sensor-registers.d.ts +53 -0
- package/dist-types/src/utils/colour-sensor-registers.js +310 -0
- package/dist-types/src/utils/marty-colour-policy.json +5 -3
- package/package.json +1 -1
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
23
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
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;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
+
if (ar || !(i in from)) {
|
|
51
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
+
ar[i] = from[i];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
+
};
|
|
57
|
+
import packageInfo from "../../package.json";
|
|
58
|
+
import colourPolicy from "./marty-colour-policy.json";
|
|
59
|
+
import { COLOUR_DATABASE_URL } from "./colour-sensor-diagnostics";
|
|
60
|
+
import isPhoneApp from "./phone-app-communication/is-phone-app";
|
|
61
|
+
import { validColourSensorProfile, colourSensorProfilePath } from "./colour-sensor-profile";
|
|
62
|
+
var PREFIX = "marty-colour-calibration-upload:";
|
|
63
|
+
var id = function () { return Array.from(window.crypto.getRandomValues(new Uint8Array(16)), function (byte) { return byte.toString(16).padStart(2, "0"); }).join(""); };
|
|
64
|
+
var memory = new Map();
|
|
65
|
+
var listeners = new Set();
|
|
66
|
+
var retry;
|
|
67
|
+
var uploading;
|
|
68
|
+
var lastError = "";
|
|
69
|
+
var notify = function () { return listeners.forEach(function (listener) { return listener(); }); };
|
|
70
|
+
var keyFor = function (entry) { return "".concat(PREFIX).concat(entry.sessionId, ":").concat(entry.attemptId, ":").concat(entry.eventId); };
|
|
71
|
+
var entries = function () {
|
|
72
|
+
var _a;
|
|
73
|
+
var result = new Map(memory);
|
|
74
|
+
try {
|
|
75
|
+
for (var index = 0; index < localStorage.length; index++) {
|
|
76
|
+
var key = localStorage.key(index);
|
|
77
|
+
if (!key.startsWith(PREFIX))
|
|
78
|
+
continue;
|
|
79
|
+
try {
|
|
80
|
+
var entry = JSON.parse(localStorage.getItem(key));
|
|
81
|
+
if ([entry.sessionId, entry.attemptId, entry.eventId].every(function (value) { return /^[a-f0-9]{32}$/.test(value); }) &&
|
|
82
|
+
keyFor(entry) === key && typeof ((_a = entry.event) === null || _a === void 0 ? void 0 : _a.type) === "string" && Number.isFinite(entry.event.recordedAtMs))
|
|
83
|
+
result.set(key, entry);
|
|
84
|
+
}
|
|
85
|
+
catch ( /* Preserve malformed local records for inspection; never upload them to arbitrary paths. */_b) { /* Preserve malformed local records for inspection; never upload them to arbitrary paths. */ }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch ( /* In-memory entries can still upload when storage is unavailable. */_c) { /* In-memory entries can still upload when storage is unavailable. */ }
|
|
89
|
+
return result;
|
|
90
|
+
};
|
|
91
|
+
var schedule = function (ms) {
|
|
92
|
+
if (ms === void 0) { ms = 500; }
|
|
93
|
+
if (retry !== undefined)
|
|
94
|
+
return;
|
|
95
|
+
retry = setTimeout(function () { retry = undefined; void flushColourCalibrationRecords(); }, ms);
|
|
96
|
+
};
|
|
97
|
+
/** Immutable event IDs allow safe retries after an unknown HTTP outcome or a reload. */
|
|
98
|
+
export var recordColourCalibrationEvent = function (ref, type, data, metadata, sequence) {
|
|
99
|
+
var entry = JSON.parse(JSON.stringify(__assign(__assign({}, ref), { eventId: id(), metadata: metadata, event: { type: type, recordedAtMs: Date.now(), sequence: sequence, data: data } })));
|
|
100
|
+
memory.set(keyFor(entry), entry);
|
|
101
|
+
try {
|
|
102
|
+
localStorage.setItem(keyFor(entry), JSON.stringify(entry));
|
|
103
|
+
}
|
|
104
|
+
catch ( /* Report undurable pending entries below. */_a) { /* Report undurable pending entries below. */ }
|
|
105
|
+
notify();
|
|
106
|
+
schedule();
|
|
107
|
+
};
|
|
108
|
+
export var getColourCalibrationUploadState = function (sessionId) {
|
|
109
|
+
var pending = Array.from(entries()).filter(function (_a) {
|
|
110
|
+
var entry = _a[1];
|
|
111
|
+
return entry.sessionId === sessionId;
|
|
112
|
+
});
|
|
113
|
+
var inMemoryOnly = false;
|
|
114
|
+
try {
|
|
115
|
+
inMemoryOnly = pending.some(function (_a) {
|
|
116
|
+
var key = _a[0];
|
|
117
|
+
return localStorage.getItem(key) === null;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (_a) {
|
|
121
|
+
inMemoryOnly = pending.length > 0;
|
|
122
|
+
}
|
|
123
|
+
return { pendingCount: pending.length, inMemoryOnly: inMemoryOnly, temporaryStorage: isPhoneApp() && pending.length > 0,
|
|
124
|
+
uploading: Boolean(uploading), error: lastError };
|
|
125
|
+
};
|
|
126
|
+
export var subscribeColourCalibrationRecords = function (listener) {
|
|
127
|
+
listeners.add(listener);
|
|
128
|
+
return function () { listeners.delete(listener); };
|
|
129
|
+
};
|
|
130
|
+
export var flushColourCalibrationRecords = function () {
|
|
131
|
+
if (uploading)
|
|
132
|
+
return uploading;
|
|
133
|
+
clearTimeout(retry);
|
|
134
|
+
retry = undefined;
|
|
135
|
+
uploading = Promise.resolve().then(function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
136
|
+
var groups, _loop_1, _i, _a, _b, path, group, state_1;
|
|
137
|
+
return __generator(this, function (_c) {
|
|
138
|
+
switch (_c.label) {
|
|
139
|
+
case 0:
|
|
140
|
+
groups = new Map();
|
|
141
|
+
entries().forEach(function (entry, key) {
|
|
142
|
+
var path = "".concat(entry.sessionId, "/calibrations/").concat(entry.attemptId);
|
|
143
|
+
groups.set(path, __spreadArray(__spreadArray([], (groups.get(path) || []), true), [[key, entry]], false));
|
|
144
|
+
});
|
|
145
|
+
_loop_1 = function (path, group) {
|
|
146
|
+
var patch, controller, timeout, response, _d, group_1, _e, entry, result, profile, indexed, storageFailure_1, failure_1;
|
|
147
|
+
return __generator(this, function (_f) {
|
|
148
|
+
switch (_f.label) {
|
|
149
|
+
case 0:
|
|
150
|
+
patch = {};
|
|
151
|
+
group.forEach(function (_a) {
|
|
152
|
+
var entry = _a[1];
|
|
153
|
+
if (entry.metadata)
|
|
154
|
+
patch.metadata = entry.metadata;
|
|
155
|
+
// Firebase multi-path PATCH appends events without replacing earlier ones.
|
|
156
|
+
patch["events/".concat(entry.eventId)] = __assign(__assign({}, entry.event), { uploadedAt: { ".sv": "timestamp" } });
|
|
157
|
+
});
|
|
158
|
+
controller = new AbortController();
|
|
159
|
+
timeout = setTimeout(function () { return controller.abort(); }, 15000);
|
|
160
|
+
_f.label = 1;
|
|
161
|
+
case 1:
|
|
162
|
+
_f.trys.push([1, 7, 8, 9]);
|
|
163
|
+
return [4 /*yield*/, fetch("".concat(COLOUR_DATABASE_URL, "/colours/").concat(path, ".json"), {
|
|
164
|
+
method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(patch), signal: controller.signal,
|
|
165
|
+
})];
|
|
166
|
+
case 2:
|
|
167
|
+
response = _f.sent();
|
|
168
|
+
if (!response.ok)
|
|
169
|
+
throw new Error(response.status === 401 || response.status === 403 ? "uploadDenied" : "uploadFailed");
|
|
170
|
+
_d = 0, group_1 = group;
|
|
171
|
+
_f.label = 3;
|
|
172
|
+
case 3:
|
|
173
|
+
if (!(_d < group_1.length)) return [3 /*break*/, 6];
|
|
174
|
+
_e = group_1[_d], entry = _e[1];
|
|
175
|
+
result = entry.event.data.result;
|
|
176
|
+
profile = result === null || result === void 0 ? void 0 : result.classificationProfile;
|
|
177
|
+
if (!(entry.event.type === "save" && entry.event.data.status === "succeeded" && validColourSensorProfile(profile))) return [3 /*break*/, 5];
|
|
178
|
+
return [4 /*yield*/, fetch("".concat(colourSensorProfilePath(profile), "/").concat(entry.attemptId, ".json"), {
|
|
179
|
+
method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(profile), signal: controller.signal,
|
|
180
|
+
})];
|
|
181
|
+
case 4:
|
|
182
|
+
indexed = _f.sent();
|
|
183
|
+
if (!indexed.ok)
|
|
184
|
+
throw new Error("uploadFailed");
|
|
185
|
+
_f.label = 5;
|
|
186
|
+
case 5:
|
|
187
|
+
_d++;
|
|
188
|
+
return [3 /*break*/, 3];
|
|
189
|
+
case 6:
|
|
190
|
+
storageFailure_1 = false;
|
|
191
|
+
group.forEach(function (_a) {
|
|
192
|
+
var key = _a[0];
|
|
193
|
+
memory.delete(key);
|
|
194
|
+
try {
|
|
195
|
+
localStorage.removeItem(key);
|
|
196
|
+
}
|
|
197
|
+
catch (_b) {
|
|
198
|
+
storageFailure_1 = true;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
lastError = storageFailure_1 ? "storageUnavailable" : "";
|
|
202
|
+
return [3 /*break*/, 9];
|
|
203
|
+
case 7:
|
|
204
|
+
failure_1 = _f.sent();
|
|
205
|
+
lastError = failure_1 instanceof Error ? failure_1.message : "uploadFailed";
|
|
206
|
+
return [2 /*return*/, "break"];
|
|
207
|
+
case 8:
|
|
208
|
+
clearTimeout(timeout);
|
|
209
|
+
return [7 /*endfinally*/];
|
|
210
|
+
case 9: return [2 /*return*/];
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
_i = 0, _a = Array.from(groups);
|
|
215
|
+
_c.label = 1;
|
|
216
|
+
case 1:
|
|
217
|
+
if (!(_i < _a.length)) return [3 /*break*/, 4];
|
|
218
|
+
_b = _a[_i], path = _b[0], group = _b[1];
|
|
219
|
+
return [5 /*yield**/, _loop_1(path, group)];
|
|
220
|
+
case 2:
|
|
221
|
+
state_1 = _c.sent();
|
|
222
|
+
if (state_1 === "break")
|
|
223
|
+
return [3 /*break*/, 4];
|
|
224
|
+
_c.label = 3;
|
|
225
|
+
case 3:
|
|
226
|
+
_i++;
|
|
227
|
+
return [3 /*break*/, 1];
|
|
228
|
+
case 4: return [2 /*return*/];
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}); }).finally(function () {
|
|
232
|
+
uploading = undefined;
|
|
233
|
+
if (entries().size)
|
|
234
|
+
schedule(lastError ? 30000 : 500);
|
|
235
|
+
notify();
|
|
236
|
+
});
|
|
237
|
+
notify();
|
|
238
|
+
return uploading;
|
|
239
|
+
};
|
|
240
|
+
export var startColourCalibrationRecordSync = function () {
|
|
241
|
+
var online = function () { void flushColourCalibrationRecords(); };
|
|
242
|
+
window.addEventListener("online", online);
|
|
243
|
+
online();
|
|
244
|
+
return function () { window.removeEventListener("online", online); };
|
|
245
|
+
};
|
|
246
|
+
export var createColourCalibrationRecorder = function (sensor, session) {
|
|
247
|
+
var _a, _b, _c;
|
|
248
|
+
var ref = { sessionId: session.sessionId, attemptId: id() };
|
|
249
|
+
var metadata = __assign(__assign({ schemaVersion: 1 }, ref), { sessionStartedAtMs: session.startedAtMs, startedAtMs: Date.now(), appVersion: packageInfo.version, device: { id: sensor.raftId, name: ((_b = (_a = sensor.raft).getFriendlyName) === null || _b === void 0 ? void 0 : _b.call(_a)) || sensor.raftId, type: sensor.raft.type,
|
|
250
|
+
firmwareVersion: ((_c = sensor.raft.systemInfo) === null || _c === void 0 ? void 0 : _c.SystemVersion) || null, connectionMethod: sensor.raft.connectionMethod || null }, sensor: { id: sensor.addon.id, name: sensor.addon.name, whoAmI: sensor.addon.whoAmI }, classifier: colourPolicy });
|
|
251
|
+
var sequence = 0;
|
|
252
|
+
return __assign(__assign({}, ref), { record: function (type, data) { return recordColourCalibrationEvent(ref, type, data, metadata, ++sequence); } });
|
|
253
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type RGB = {
|
|
2
|
+
red: number;
|
|
3
|
+
green: number;
|
|
4
|
+
blue: number;
|
|
5
|
+
};
|
|
6
|
+
export type ColourSignalProfile = {
|
|
7
|
+
airMin: RGB;
|
|
8
|
+
airMax: RGB;
|
|
9
|
+
margin: RGB;
|
|
10
|
+
};
|
|
11
|
+
export type ColourName = "red" | "yellow" | "green" | "blue" | "purple" | "air" | "unclear";
|
|
12
|
+
/** Published channels are white-normalised by the SDK; do not clamp them for classification. */
|
|
13
|
+
export declare const classifyColour: (values: RGB & {
|
|
14
|
+
clear: number;
|
|
15
|
+
air: boolean;
|
|
16
|
+
}, profile?: ColourSignalProfile) => {
|
|
17
|
+
classifiedColour: ColourName;
|
|
18
|
+
colourWithoutAirOverride: ColourName;
|
|
19
|
+
hue: number | null;
|
|
20
|
+
chroma: number;
|
|
21
|
+
saturation: number;
|
|
22
|
+
signalAboveAir: boolean;
|
|
23
|
+
signalSource: string;
|
|
24
|
+
classificationReason: string;
|
|
25
|
+
};
|
|
26
|
+
export declare const colourChannelsFromValues: (vals: Record<string, number | boolean>) => {
|
|
27
|
+
red: number;
|
|
28
|
+
green: number;
|
|
29
|
+
blue: number;
|
|
30
|
+
clear: number;
|
|
31
|
+
air: boolean;
|
|
32
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import policy from "./marty-colour-policy.json";
|
|
2
|
+
/** Published channels are white-normalised by the SDK; do not clamp them for classification. */
|
|
3
|
+
export var classifyColour = function (values, profile) {
|
|
4
|
+
var r = values.red, g = values.green, b = values.blue, clear = values.clear, air = values.air;
|
|
5
|
+
var valid = [r, g, b, clear].every(function (value) { return Number.isFinite(value) && value >= 0; }) && typeof air === "boolean";
|
|
6
|
+
var maximum = Math.max(r, g, b);
|
|
7
|
+
var chroma = maximum - Math.min(r, g, b);
|
|
8
|
+
var hue = chroma === 0 ? NaN : r > g && r > b ? (((g - b) / chroma) % 6) * 60 :
|
|
9
|
+
g > b ? ((b - r) / chroma + 2) * 60 : ((r - g) / chroma + 4) * 60;
|
|
10
|
+
if (hue < 0)
|
|
11
|
+
hue += 360;
|
|
12
|
+
var saturation = maximum > 0 ? chroma / maximum : 0;
|
|
13
|
+
var match = valid ? policy.boundaries.find(function (colour) { return colour.hue[0] <= hue && hue <= colour.hue[1] &&
|
|
14
|
+
colour.chroma[0] <= chroma && chroma <= colour.chroma[1]; }) : undefined;
|
|
15
|
+
var exceedsAir = !profile || ["red", "green", "blue"].some(function (channel) {
|
|
16
|
+
return values[channel] > profile.airMax[channel] + profile.margin[channel];
|
|
17
|
+
});
|
|
18
|
+
var confident = valid && exceedsAir && chroma >= policy.signal.minimumChroma &&
|
|
19
|
+
saturation >= policy.signal.minimumSaturation;
|
|
20
|
+
var colourWithoutAirOverride = confident && match ? match.name : "unclear";
|
|
21
|
+
var classifiedColour = colourWithoutAirOverride !== "unclear" ? colourWithoutAirOverride :
|
|
22
|
+
valid && air ? "air" : "unclear";
|
|
23
|
+
return { classifiedColour: classifiedColour, colourWithoutAirOverride: colourWithoutAirOverride, hue: Number.isFinite(hue) ? hue : null, chroma: chroma, saturation: saturation, signalAboveAir: exceedsAir, signalSource: profile ? "calibratedAir" : "defaultRules", classificationReason: !valid ? "invalid" :
|
|
24
|
+
!exceedsAir ? "withinCalibratedAir" : confident && match ? air ? "rgbOverridesFirmwareAir" : "rgbColour" :
|
|
25
|
+
air ? "firmwareAir" : "weakOrUnknownColour" };
|
|
26
|
+
};
|
|
27
|
+
export var colourChannelsFromValues = function (vals) {
|
|
28
|
+
var values = {};
|
|
29
|
+
for (var key in vals)
|
|
30
|
+
for (var _i = 0, _a = ["Red", "Green", "Blue", "Clear", "Air"]; _i < _a.length; _i++) {
|
|
31
|
+
var channel = _a[_i];
|
|
32
|
+
if (key.includes(channel))
|
|
33
|
+
values[channel.toLowerCase()] = vals[key];
|
|
34
|
+
}
|
|
35
|
+
return { red: values.red, green: values.green, blue: values.blue,
|
|
36
|
+
clear: values.clear, air: [true, false, 0, 1].includes(values.air) ? Boolean(values.air) : undefined };
|
|
37
|
+
};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import colourPolicy from "./marty-colour-policy.json";
|
|
2
|
+
import { ColourSignalProfile } from "./colour-classifier";
|
|
3
|
+
import { ColourSensorProfile } from "./colour-sensor-profile";
|
|
4
|
+
import type { RaftObserver } from "../application/RAFTs/RaftObserver";
|
|
5
|
+
import type { RestMessageOptions } from "../types/communication-between-apps/wrapper-communication";
|
|
6
|
+
import { SensorRead, RawColourFrame, ColourSensorSetup } from "./colour-sensor-registers";
|
|
7
|
+
export declare const CARD_COLOURS: readonly ["green", "purple", "yellow", "blue", "red"];
|
|
8
|
+
export type CardColour = typeof CARD_COLOURS[number];
|
|
9
|
+
export declare const CAPTURE_TARGETS: readonly ["green", "purple", "yellow", "blue", "red", "air"];
|
|
10
|
+
export type CaptureTarget = typeof CAPTURE_TARGETS[number];
|
|
11
|
+
export declare const COLOUR_DATABASE_URL = "https://platforms-error-logging-default-rtdb.europe-west1.firebasedatabase.app";
|
|
12
|
+
export declare const BLOCKS_COLOUR_BOUNDARIES: {
|
|
13
|
+
hue: number[];
|
|
14
|
+
chroma: number[];
|
|
15
|
+
clear: number[];
|
|
16
|
+
name: string;
|
|
17
|
+
}[];
|
|
18
|
+
type SensorAddon = {
|
|
19
|
+
id: number;
|
|
20
|
+
name: string;
|
|
21
|
+
whoAmI: string;
|
|
22
|
+
status?: number;
|
|
23
|
+
vals: Record<string, number | boolean>;
|
|
24
|
+
};
|
|
25
|
+
export type DiagnosticRaft = {
|
|
26
|
+
type: string;
|
|
27
|
+
isVerified: boolean;
|
|
28
|
+
connectionInstanceId?: string;
|
|
29
|
+
getFriendlyName?: () => string;
|
|
30
|
+
systemInfo?: {
|
|
31
|
+
SystemVersion?: string;
|
|
32
|
+
HardwareVersion?: string;
|
|
33
|
+
} | null;
|
|
34
|
+
connectionMethod?: string | null;
|
|
35
|
+
sendRestMessage?: (message: string, params?: object, options?: RestMessageOptions) => Promise<unknown>;
|
|
36
|
+
subscribe?: (observer: RaftObserver, topics: string[]) => void;
|
|
37
|
+
unsubscribe?: (observer: RaftObserver) => void;
|
|
38
|
+
raftStateInfo?: {
|
|
39
|
+
addOnInfoValidMs: number;
|
|
40
|
+
addOnInfo: {
|
|
41
|
+
addons: SensorAddon[];
|
|
42
|
+
};
|
|
43
|
+
powerValidMs?: number;
|
|
44
|
+
power?: {
|
|
45
|
+
powerStatus: {
|
|
46
|
+
power5VIsOn: boolean;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
} | null;
|
|
51
|
+
};
|
|
52
|
+
export type ColourSensor = {
|
|
53
|
+
key: string;
|
|
54
|
+
raftId: string;
|
|
55
|
+
raft: DiagnosticRaft;
|
|
56
|
+
addon: SensorAddon;
|
|
57
|
+
};
|
|
58
|
+
export type ColourReading = {
|
|
59
|
+
observedAtMs: number;
|
|
60
|
+
receivedAtMs: number;
|
|
61
|
+
ageMs: number;
|
|
62
|
+
red: number;
|
|
63
|
+
green: number;
|
|
64
|
+
blue: number;
|
|
65
|
+
clear: number;
|
|
66
|
+
isOnAir: boolean;
|
|
67
|
+
hex: string;
|
|
68
|
+
hue: number | null;
|
|
69
|
+
chroma: number;
|
|
70
|
+
classifiedColour: string;
|
|
71
|
+
colourWithoutAirOverride?: string;
|
|
72
|
+
saturation?: number;
|
|
73
|
+
signalAboveAir?: boolean;
|
|
74
|
+
classificationReason?: string;
|
|
75
|
+
signalSource?: string;
|
|
76
|
+
irFootSensors?: SensorAddon[];
|
|
77
|
+
publishedValues: Record<string, number | boolean>;
|
|
78
|
+
sensorStatus: number | null;
|
|
79
|
+
};
|
|
80
|
+
export type ColourSnapshot = {
|
|
81
|
+
schemaVersion: 1 | 2;
|
|
82
|
+
sessionId: string;
|
|
83
|
+
sessionStartedAtMs: number;
|
|
84
|
+
captureId: string;
|
|
85
|
+
expectedColour: CaptureTarget;
|
|
86
|
+
startedAtMs: number;
|
|
87
|
+
finishedAtMs: number;
|
|
88
|
+
appVersion: string;
|
|
89
|
+
classifier: {
|
|
90
|
+
source: string;
|
|
91
|
+
airFlagTakesPrecedence: boolean;
|
|
92
|
+
boundaries: typeof BLOCKS_COLOUR_BOUNDARIES;
|
|
93
|
+
signal?: typeof colourPolicy.signal;
|
|
94
|
+
profile?: ColourSensorProfile;
|
|
95
|
+
clearBoundsUsedForClassification?: boolean;
|
|
96
|
+
};
|
|
97
|
+
device: {
|
|
98
|
+
id: string;
|
|
99
|
+
type: string;
|
|
100
|
+
name: string;
|
|
101
|
+
firmwareVersion: string | null;
|
|
102
|
+
connectionMethod: string | null;
|
|
103
|
+
};
|
|
104
|
+
sensor: {
|
|
105
|
+
id: number;
|
|
106
|
+
name: string;
|
|
107
|
+
whoAmI: string;
|
|
108
|
+
};
|
|
109
|
+
sampleIntervalMs: number;
|
|
110
|
+
sampleCount: number;
|
|
111
|
+
samples: ColourReading[];
|
|
112
|
+
sampleWindowStartedAtMs?: number;
|
|
113
|
+
sensorSetup?: ColourSensorSetup;
|
|
114
|
+
rawSamples?: SensorRead<RawColourFrame>[];
|
|
115
|
+
powerStatus?: {
|
|
116
|
+
receivedAtMs: number;
|
|
117
|
+
values: {
|
|
118
|
+
power5VIsOn: boolean;
|
|
119
|
+
[key: string]: unknown;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
export type ColourSession = {
|
|
124
|
+
schemaVersion: 1;
|
|
125
|
+
sessionId: string;
|
|
126
|
+
startedAtMs: number;
|
|
127
|
+
captures: {
|
|
128
|
+
snapshot: ColourSnapshot;
|
|
129
|
+
uploaded: boolean;
|
|
130
|
+
}[];
|
|
131
|
+
};
|
|
132
|
+
export type DiagnosticErrorCode = "sensorDisconnected" | "staleReading" | "invalidReading" | "backgrounded" | "uploadDenied" | "uploadFailed" | "cancelled" | "sensorInitialising" | "sensorAsleep" | "sensorOffline" | "sensorPowerFailed" | "calibrationReconnectRequired" | "sensorBusy";
|
|
133
|
+
export declare class ColourDiagnosticError extends Error {
|
|
134
|
+
code: DiagnosticErrorCode;
|
|
135
|
+
constructor(code: DiagnosticErrorCode);
|
|
136
|
+
}
|
|
137
|
+
export declare const newColourSession: () => ColourSession;
|
|
138
|
+
export declare const getColourSensors: (raftId: string) => ColourSensor[];
|
|
139
|
+
export declare const assertColourSensorActive: (sensor: ColourSensor, signal: AbortSignal) => void;
|
|
140
|
+
export declare const interpretColour: (vals: Record<string, number | boolean>, profile?: ColourSignalProfile) => {
|
|
141
|
+
red: number;
|
|
142
|
+
green: number;
|
|
143
|
+
blue: number;
|
|
144
|
+
clear: number;
|
|
145
|
+
isOnAir: boolean;
|
|
146
|
+
hex: string;
|
|
147
|
+
classifiedColour: import("./colour-classifier").ColourName;
|
|
148
|
+
colourWithoutAirOverride: import("./colour-classifier").ColourName;
|
|
149
|
+
hue: number | null;
|
|
150
|
+
chroma: number;
|
|
151
|
+
saturation: number;
|
|
152
|
+
signalAboveAir: boolean;
|
|
153
|
+
signalSource: string;
|
|
154
|
+
classificationReason: string;
|
|
155
|
+
};
|
|
156
|
+
export declare const readColourSensor: (sensor: ColourSensor) => ColourReading;
|
|
157
|
+
export declare const captureColourSnapshot: (sensor: ColourSensor, expectedColour: CaptureTarget, session: ColourSession, signal: AbortSignal) => Promise<ColourSnapshot>;
|
|
158
|
+
export declare const uploadColourSnapshot: (snapshot: ColourSnapshot, signal: AbortSignal) => Promise<void>;
|
|
159
|
+
export declare const loadColourSession: () => ColourSession;
|
|
160
|
+
export declare const persistColourSession: (session: ColourSession) => boolean;
|
|
161
|
+
export declare const downloadColourSession: (session: ColourSession) => void;
|
|
162
|
+
export {};
|