Skip to content

Commit

Permalink
Trying to migrate backend to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
GermanBluefox committed Sep 24, 2024
1 parent add11f5 commit e74a77d
Show file tree
Hide file tree
Showing 9 changed files with 1,286 additions and 0 deletions.
43 changes: 43 additions & 0 deletions build-backend/cameras/Eufy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_url_1 = require("node:url");
const RTSP_1 = __importDefault(require("./RTSP"));
class EufyCamera extends RTSP_1.default {
async init(settings) {
if (settings.useOid && !settings.oid) {
throw new Error(`Invalid object ID: "${settings.oid}"`);
}
// check parameters
if (!settings.useOid && (!settings.ip || typeof settings.ip !== 'string')) {
throw new Error(`Invalid IP: "${settings.ip}"`);
}
const _settings = JSON.parse(JSON.stringify(settings));
if (settings.useOid) {
const url = await this.adapter.getForeignStateAsync(settings.oid);
const parts = settings.oid.split('.');
parts.pop();
parts.push('rtsp_stream');
const rtspEnabled = await this.adapter.getForeignStateAsync(parts.join('.'));
if (rtspEnabled && !rtspEnabled.val) {
await this.adapter.setForeignStateAsync(parts.join('.'), true);
}
if (url?.val) {
const u = new node_url_1.URL(url.val);
_settings.ip = u.hostname;
_settings.port = u.port;
_settings.urlPath = u.pathname;
_settings.username = u.username;
this.decodedPassword = u.password;
}
}
else {
_settings.port = '80';
_settings.urlPath = '/live0';
}
await super.init(_settings);
}
}
exports.default = EufyCamera;
124 changes: 124 additions & 0 deletions build-backend/cameras/Generic.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const sharp_1 = __importDefault(require("sharp"));
const moment_1 = __importDefault(require("moment/moment"));
class GenericCamera {
runningRequest = null;
settings;
adapter;
cacheTimeout = 0;
cache = null;
constructor(adapter) {
this.adapter = adapter;
}
async unload() {
// do nothing
}
async getCameraImage(querySettings) {
if (!this.settings) {
throw new Error('init not called');
}
this.adapter.log.debug(`Request ${this.settings.type} ${this.settings.ip || this.settings.url || ''} ${this.settings.name}`);
const params = {
w: parseInt(querySettings?.w || this.settings.width, 10) || 0,
h: parseInt(querySettings?.h || this.settings.height, 10) || 0,
angle: parseInt(querySettings?.angle || this.settings.angle, 10) || 0,
};
if (!querySettings?.noCache &&
this.cache &&
this.cache.ts > Date.now() &&
JSON.stringify(this.cache.params) === JSON.stringify(params)) {
this.adapter.log.debug(`Take from cache ${this.settings.name} ${this.settings.type} ${this.settings.ip || this.settings.url}`);
return this.cache.data;
}
let data = await this.process();
if (data) {
data = await this.resizeImage(data, params.w, params.h);
data = await this.rotateImage(data, params.angle);
data = await this.addTextToImage(data, this.settings.addTime ? this.adapter.config.dateFormat || 'LTS' : null, this.settings.title);
if (this.cacheTimeout) {
this.cache = {
data,
ts: Date.now() + this.cacheTimeout,
params: JSON.stringify(params),
};
}
await this.adapter.writeFileAsync(this.adapter.namespace, `/${this.settings.name}.jpg`, Buffer.from(data.body));
return data;
}
throw new Error('No data from camera');
}
resizeImage(data, width, height) {
if (!sharp_1.default) {
this.adapter.log.warn('Module sharp is not installed. Please install it to resize images');
return Promise.resolve({ body: data.body, contentType: 'image/jpeg' });
}
if (!width && !height) {
return (0, sharp_1.default)(data.body)
.jpeg()
.toBuffer()
.then(body => ({ body, contentType: 'image/jpeg' }));
}
return (0, sharp_1.default)(data.body)
.resize(width || null, height || null)
.jpeg()
.toBuffer()
.then(body => ({ body, contentType: 'image/jpeg' }));
}
rotateImage(data, angle) {
if (!angle) {
return (0, sharp_1.default)(data.body)
.jpeg()
.toBuffer()
.then(body => ({ body, contentType: 'image/jpeg' }));
}
return (0, sharp_1.default)(data.body)
.rotate(angle)
.jpeg()
.toBuffer()
.then(body => ({ body, contentType: 'image/jpeg' }));
}
async addTextToImage(data, dateFormat, title) {
if (!dateFormat && !title) {
return data;
}
const date = dateFormat ? (0, moment_1.default)().locale(this.adapter.language).format(dateFormat) : '';
const metadata = await (0, sharp_1.default)(data.body).metadata();
const layers = [];
if (title) {
layers.push({
input: {
text: {
text: title,
dpi: metadata.height * 0.2,
},
},
top: Math.round(metadata.height * 0.95),
left: Math.round(metadata.width * 0.01),
blend: 'add',
});
}
if (date) {
layers.push({
input: {
text: {
text: date,
dpi: metadata.height * 0.2,
},
},
top: Math.round(metadata.height * 0.02),
left: Math.round(metadata.width * 0.01),
blend: 'add',
});
}
return (0, sharp_1.default)(data.body)
.composite(layers)
.jpeg()
.toBuffer()
.then(body => ({ body, contentType: 'image/jpeg' }));
}
}
exports.default = GenericCamera;
21 changes: 21 additions & 0 deletions build-backend/cameras/Hikam.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const RTSP_1 = __importDefault(require("./RTSP"));
// documentation https://www.wiwacam.com/de/mw1-minikamera-kurzanleitung-und-faq/
// https://support.hikam.de/support/solutions/articles/16000070656-zugriff-auf-kameras-der-2-generation-via-onvif-f%C3%BCr-s6-q8-a7-2-generation-
class HikamCamera extends RTSP_1.default {
async init(settings) {
// check parameters
if (!settings.ip || typeof settings.ip !== 'string') {
throw new Error(`Invalid IP: "${settings.ip}"`);
}
const _settings = JSON.parse(JSON.stringify(settings));
_settings.port = '554';
_settings.urlPath = settings.quality === 'high' ? '/stream=0' : '/stream=1';
await super.init(_settings);
}
}
exports.default = HikamCamera;
Loading

0 comments on commit e74a77d

Please sign in to comment.