homebridge-smartsystem
Version:
SmartServer (Proxy TCP sockets to the cloud, Smappee MQTT, Duotecno IP Nodes, Homekit interface)
196 lines • 8.04 kB
JavaScript
"use strict";
// Shelly PM implementation
// Johan Coppieters, Jul 2022.
//
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Shelly = void 0;
const logger_1 = require("../duotecno/logger");
const powerbase_1 = require("./powerbase");
const api_1 = require("../duotecno/api");
const HTTPstatus = {
"wifi_sta": {
"connected": true,
"ssid": "Tele Coppieters",
"ip": "192.168.0.95",
"rssi": -73
},
"cloud": {
"enabled": true,
"connected": true
},
"mqtt": {
"connected": false
},
"time": "18:17",
"unixtime": 1663863464,
"serial": 7,
"has_update": true,
"mac": "C45BBE7928B9",
"cfg_changed_cnt": 1,
"actions_stats": { "skipped": 0 },
"relays": [{ "ison": true, "has_timer": false, "timer_started": 0, "timer_duration": 0, "timer_remaining": 0, "overpower": false, "is_valid": true, "source": "http" }],
"emeters": [
{ "power": 10.66, "pf": 1.00, "current": 0.08, "voltage": 232.06, "is_valid": true, "total": 5.3, "total_returned": 0.0 },
{ "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.06, "is_valid": true, "total": 0.0, "total_returned": 0.0 },
{ "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.05, "is_valid": true, "total": 0.0, "total_returned": 0.0 }
],
"total_power": 10.66,
"fs_mounted": true,
"update": { "status": "pending", "has_update": true, "new_version": "20220830-080542/v1.12-3EM-gcf4f7c2", "old_version": "20220209-094824/v1.11.8-g8c7bb8d" },
"ram_total": 49440,
"ram_free": 30960,
"fs_size": 233681,
"fs_free": 156875,
"uptime": 1364
};
const HttpEMeter0 = {
"power": 10.95,
"pf": 1.00,
"current": 0.08,
"voltage": 231.21,
"is_valid": true,
"total": 7.2,
"total_returned": 0.0
};
class Shelly extends powerbase_1.PowerBase {
constructor(system) {
super("shelly", system);
this.timer = null;
this.meters = [];
this.nrPhases = 0;
// init is called by super
}
//
// return data for ejs pages
//
// async getData(context: Context, message: String): Promise<any> {
// // nothing special... for now
// return super.getData(context, message);
// }
//
// config mgt
//
updateConfig(config) {
const _super = Object.create(null, {
updateConfig: { get: () => super.updateConfig }
});
return __awaiter(this, void 0, void 0, function* () {
this.config.addresses = config.addresses;
return _super.updateConfig.call(this, config);
});
}
subscribe() {
return __awaiter(this, void 0, void 0, function* () {
const kInterval = 5;
if (this.config.address) {
yield this.getDeviceConfig(this.config.address, true);
}
if (this.config.addresses) {
const list = this.config.addresses.split(",");
for (let inx in list) {
const phases = (this.config.address) ? false : (inx == "0");
yield this.getDeviceConfig(list[inx], phases);
}
}
(0, logger_1.debug)("shelly", "meters: " + JSON.stringify(this.meters));
if (this.meters && this.meters.length) {
this.timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
this.realtimeCounter += kInterval;
// fetch data
const ok = yield this.fetchData();
if (ok)
this.consume();
// call process/bindings/rules
this.applyBindings();
this.applyRules();
}), kInterval * 1000);
}
else {
(0, logger_1.log)("shelly", "No Shelly PM devices configured");
}
});
}
unsubscribe() {
return __awaiter(this, void 0, void 0, function* () {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
});
}
getDeviceConfig(address, phases) {
return __awaiter(this, void 0, void 0, function* () {
try {
// debug("shelly", "fetching from " + address + "/status");
const res = yield (0, api_1.get)(address, 80, "/status", undefined);
(0, logger_1.debug)("shelly", "received status from " + address + " -> " + res);
const status = JSON.parse(res);
// enrich meter with its address and index + add to the global meter list
status.emeters.forEach((m, inx) => {
m.index = inx; // index with this PM device
m.phase = phases;
if (phases) {
m.phaseNr = this.nrPhases;
this.nrPhases++;
}
else {
m.phaseNr = -1;
}
m.address = address;
this.meters.push(m);
});
}
catch (error) {
(0, logger_1.err)("shelly", error.message);
}
});
}
fetchData() {
return __awaiter(this, void 0, void 0, function* () {
try {
for (let meter in this.meters) {
// debug("shelly", "fetching from " + this.config.address + "/emeter/" + meter);
const res = yield (0, api_1.get)(this.meters[meter].address, 80, "/emeter/" + this.meters[meter].index, undefined);
(0, logger_1.debug)("shelly", "received meter: " + meter + " -> " + res);
this.meters[meter] = Object.assign(Object.assign({}, this.meters[meter]), JSON.parse(res));
}
;
return true;
}
catch (error) {
(0, logger_1.err)("shelly", error.message || error);
return false;
}
});
}
consume() {
// copy this.meters into the powerbase structures
this.meters.forEach((meter, inx) => {
this.channels[inx] = {
name: "Meter " + (inx + 1), type: "CT", flow: "PRODUCTION",
power: meter.power, exportEnergy: meter.total_returned, importEnergy: meter.total, phaseId: meter.phaseNr,
current: meter.power / meter.voltage, apparentPower: 0, cosPhi: 0, formula: "", voltage: meter.voltage
};
});
this.voltages = [0, 0, 0];
this.meters.filter(m => m.phase).forEach(m => this.voltages[m.phaseNr] = m.voltage);
this.realtime = { totalPower: this.meters.reduce((prev, curr) => curr.power + prev, 0),
totalReactivePower: 0,
totalExportEnergy: this.meters.reduce((prev, curr) => curr.total_returned + prev, 0),
totalImportEnergy: this.meters.reduce((prev, curr) => curr.total + prev, 0),
monitorStatus: 0, utcTimeStamp: new Date().getTime() };
this.production = this.realtime.totalPower;
this.consumption = this.realtime.totalReactivePower;
}
}
exports.Shelly = Shelly;
//# sourceMappingURL=shelly.js.map