timeline-state-resolver
Version:
Have timeline, control stuff
166 lines • 6.23 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PanasonicPtzHttpInterface = exports.PanasonicFocusMode = exports.PanasonicPtzCamera = void 0;
const _ = require("underscore");
const events_1 = require("events");
const got_1 = require("got");
const querystring = require("querystring");
const commands_1 = require("./commands");
const PROBE_INTERVAL = 10 * 1000; // Probe every 10s
/**
* Low level device class for Panasonic PTZ devices executing a
* basic queue.
*/
class PanasonicPtzCamera extends events_1.EventEmitter {
constructor(url, commandDelay = 130) {
super();
this._commandQueue = [];
this._executeQueueTimeout = [];
this._commandDelay = commandDelay;
this._url = url;
}
async sendCommand(command) {
const p = new Promise((resolve, reject) => {
this._commandQueue.push({ command: command, executing: false, resolve: resolve, reject: reject });
});
if (this._commandQueue.filter((i) => i.executing).length === 0)
this._executeQueue();
return p;
}
dispose() {
this._commandQueue = [];
_.each(this._executeQueueTimeout, (item) => {
clearTimeout(item);
});
}
_dropFromQueue(item) {
const index = this._commandQueue.findIndex((i) => i === item);
if (index >= 0) {
this._commandQueue.splice(index, 1);
}
else {
throw new Error(`Command ${item.command} should be dropped from the queue, but could not be found!`);
}
}
_executeQueue() {
const qItem = this._commandQueue.find((i) => !i.executing);
if (!qItem) {
return;
}
const queryUrl = this._url + '?' + querystring.stringify({ cmd: qItem.command, res: '1' });
this.emit('debug', 'Command sent', queryUrl);
qItem.executing = true;
got_1.default
.get(queryUrl)
.then((response) => {
this._dropFromQueue(qItem);
qItem.resolve(response.body);
})
.catch((error) => {
this.emit('error', error);
this._dropFromQueue(qItem);
qItem.reject(error);
});
// find any commands that aren't executing yet and execute one after 130ms
if (this._commandQueue.filter((i) => !i.executing).length > 0) {
const timeout = setTimeout(() => {
// remove from timeouts list
const index = this._executeQueueTimeout.indexOf(timeout);
if (index >= 0) {
this._executeQueueTimeout.splice(index, 1);
}
this._executeQueue();
}, this._commandDelay);
// add to timeouts list so that we can cancel them when disposing
this._executeQueueTimeout.push(timeout);
}
}
}
exports.PanasonicPtzCamera = PanasonicPtzCamera;
var PanasonicFocusMode;
(function (PanasonicFocusMode) {
PanasonicFocusMode[PanasonicFocusMode["MANUAL"] = 0] = "MANUAL";
PanasonicFocusMode[PanasonicFocusMode["AUTO"] = 1] = "AUTO";
})(PanasonicFocusMode = exports.PanasonicFocusMode || (exports.PanasonicFocusMode = {}));
var PanasonicHttpResponse;
(function (PanasonicHttpResponse) {
PanasonicHttpResponse["POWER_MODE_ON"] = "p1";
PanasonicHttpResponse["POWER_MODE_STBY"] = "p0";
PanasonicHttpResponse["POWER_MODE_TURNING_ON"] = "p3";
PanasonicHttpResponse["ERROR_1"] = "E1";
PanasonicHttpResponse["ERROR_2"] = "E2";
PanasonicHttpResponse["ERROR_3"] = "E3";
})(PanasonicHttpResponse || (PanasonicHttpResponse = {}));
/**
* High level methods for interfacing with a panasonic PTZ camera. This class
* depends on the PanasonicPtzCamera class.
*/
class PanasonicPtzHttpInterface extends events_1.EventEmitter {
constructor(host, port, https) {
super();
this._connected = false;
this._device = new PanasonicPtzCamera((https ? 'https' : 'http') + '://' + host + (port ? ':' + port : '') + '/cgi-bin/aw_ptz');
this._device.on('error', (err) => {
this.emit('error', err);
});
this._device.on('debug', (...args) => {
this.emit('debug', ...args);
});
}
init() {
const check = () => {
this.ping()
.then((result) => {
this._connected = result !== commands_1.PowerMode.POWER_MODE_STBY;
})
.catch(() => {
this._connected = false;
});
};
this._pingInterval = setInterval(check, PROBE_INTERVAL);
check(); // do a check right away
}
static _isError(response) {
if (response === PanasonicHttpResponse.ERROR_1 ||
response === PanasonicHttpResponse.ERROR_2 ||
response === PanasonicHttpResponse.ERROR_3) {
return true;
}
else {
return false;
}
}
dispose() {
this._device.dispose();
if (this._pingInterval)
clearInterval(this._pingInterval);
this._connected = false;
}
get connected() {
return this._connected;
}
/**
* Ping a camera by checking its power status. Will return true if the camera is on, false if it's off but reachable and will fail otherwise
* @returns {Promose<boolean | string>} A promise: true if the camera is ON, false if the camera is off, 'turningOn' if transitioning from STBY to ON
* @memberof PanasonicPtzHttpInterface
*/
async ping() {
return this.executeCommand(new commands_1.PowerModeQuery());
}
async executeCommand(command) {
let response;
try {
response = await this._device.sendCommand(command.serialize());
}
catch (error) {
this.emit('disconnected', error);
throw error;
}
if (PanasonicPtzHttpInterface._isError(response)) {
throw new Error(`Device returned an error: ${response}`);
}
return command.deserializeResponse(response);
}
}
exports.PanasonicPtzHttpInterface = PanasonicPtzHttpInterface;
//# sourceMappingURL=connection.js.map