homebridge-smartsystem
Version:
SmartServer (Proxy Websockets to TCP sockets, Smappee MQTT, Duotecno IP Nodes, Homekit interface)
227 lines (189 loc) • 6.98 kB
text/typescript
// P1 implementation
// Johan Coppieters, Jul 2022.
//
import { System } from "../duotecno/system";
import { P1Config } from "../duotecno/types";
import { err, log } from "../duotecno/logger";
import { PowerBase } from "./powerbase";
import { debug } from "../duotecno/logger";
import { get } from "../duotecno/api";
/* http://192.168.0.214/api/v1/data
{
"smr_version":50,
"meter_model":"Fluvius 253769484_A",
"wifi_ssid":"Tele Coppieters",
"wifi_strength":32,
"total_power_import_t1_kwh":10247.015,
"total_power_import_t2_kwh":18548.61,
"total_power_export_t1_kwh":5890.344,
"total_power_export_t2_kwh":2191.808,
"active_power_w":461,
"active_power_l1_w":400,
"active_power_l2_w":0,
"active_power_l3_w":60,
"total_gas_m3":null,
"gas_timestamp":null}
}
* https://jensd.be/1205/linux/data-lezen-van-de-belgische-digitale-meter-met-de-p1-poort
* http://192.168.0.214/api/v1/telegram
/FLU5\253769484_A
0-0:96.1.4(50216)
0-0:96.1.1(3153414733313030303539333731)
0-0:1.0.0(220720162529S)
1-0:1.8.1(010246.991*kWh)
1-0:1.8.2(018548.610*kWh)
1-0:2.8.1(005890.344*kWh)
1-0:2.8.2(002191.808*kWh)
0-0:96.14.0(0001)
1-0:1.7.0(00.489*kW)
1-0:2.7.0(00.000*kW)
1-0:21.7.0(00.405*kW)
1-0:41.7.0(00.000*kW)
1-0:61.7.0(00.084*kW)
1-0:22.7.0(00.000*kW)
1-0:42.7.0(00.000*kW)
1-0:62.7.0(00.000*kW)
1-0:32.7.0(233.8*V)
1-0:52.7.0(000.0*V)
1-0:72.7.0(234.4*V)
1-0:31.7.0(002.11*A)
1-0:51.7.0(001.10*A)
1-0:71.7.0(001.92*A)
0-0:96.3.10(1)
0-0:17.0.0(999.9*kW)
1-0:31.4.0(999*A)
0-0:96.13.0()
!56E6
fetchData => {
1.7.0:{value: 0.469, unit: 'kW'}
1.8.1:{value: 10247.463, unit: 'kWh'}
1.8.2:{value: 18548.61, unit: 'kWh'}
2.7.0:{value: 0, unit: 'kW'}
2.8.1:{value: 5890.344, unit: 'kWh'}
2.8.2:{value: 2191.808, unit: 'kWh'}
21.7.0:{value: 0.432, unit: 'kW'}
22.7.0:{value: 0, unit: 'kW'}
31.4.0:{value: 999, unit: 'A'}
31.7.0:{value: 2.14, unit: 'A'}
32.7.0:{value: 233.7, unit: 'V'}
41.7.0:{value: 0, unit: 'kW'}
42.7.0:{value: 0, unit: 'kW'}
51.7.0:{value: 1.03, unit: 'A'}
52.7.0:{value: 0, unit: 'V'}
61.7.0:{value: 0.036, unit: 'kW'}
62.7.0:{value: 0, unit: 'kW'}
71.7.0:{value: 1.93, unit: 'A'}
72.7.0:{value: 233.5, unit: 'V'}
}
*/
interface P1Data {
[key: string]: {value: number; unit: string}
}
export class P1 extends PowerBase {
config: P1Config; // redefine
timer: NodeJS.Timer;
constructor(system: System) {
super("p1", system);
// readconfig and init are 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
//
// async updateConfig(config: any) {
// // nothing special... for now
// return super.updateConfig(config);
// }
async subscribe() {
const kInterval = 5;
log("p1", "connecting to P1: " + this.config.address);
if (this.config.address) {
this.timer = setInterval(async () => {
this.realtimeCounter += kInterval;
// fetch data
const message = await this.fetchData();
if (message)
this.consume(message);
// call process/bindings/rules
this.applyBindings();
this.applyRules();
}, kInterval * 1000);
}
}
async unsubscribe() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
}
async fetchData(): Promise<P1Data> {
try {
debug("p1", "fetching from " + this.config.address + "/api/v1/telegram");
const res = await get(this.config.address, 80, "/api/v1/telegram", undefined);
debug("p1", "received: " + res);
const result: P1Data = {};
res.split("\r\n").filter(l => (l[0] === '1')).map(L => {
// 0-0:1.0.0(220720172521S)
// 1-0:62.7.0(00.135*kW)
const S = L.split(":")[1]; // remove preamble 1-0
if (!S) return undefined; // no key-value -> remove
const V = S.split("("); // split "key(value"
const key = V[0];
if (V.length < 2) return undefined; // no value -> remove
const value = V[1].substring(0, V[1].length - 1); // remove last ")"
const VU = value.split("*"); // split "value*unit"
return { key, value: VU[0], unit: VU[1]};
}).forEach(R =>
result[R.key] = {value: parseFloat(R.value), unit: R.unit}
);
return result;
} catch(error) {
err("p1", "error fetching data: " + JSON.stringify(error));
return null;
}
}
consume(data: P1Data) {
if (! data['32.7.0']) return;
this.channels = {
0: {
name: "Zonnepanelen L1", type: "CT", flow: "PRODUCTION", voltage: data['32.7.0']?.value,
power: data['22.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 0,
current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
1: {
name: "Zonnepanelen L2", type: "CT", flow: "PRODUCTION", voltage: data['52.7.0']?.value,
power: data['42.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 1,
current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
2: {
name: "Zonnepanelen L3", type: "CT", flow: "PRODUCTION", voltage: data['72.7.0']?.value,
power: data['62.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 2,
current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
3: {
name: "Grid L1", type: "CT", flow: "CONSUMPTION", voltage: data['32.7.0']?.value,
power: data['21.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 0,
current: data['31.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""},
4: {
name: "Grid L2", type: "CT", flow: "CONSUMPTION", voltage: data['52.7.0']?.value,
power: data['41.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 1,
current: data['51.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""},
5: {
name: "Grid L3", type: "CT", flow: "CONSUMPTION", voltage: data['72.7.0']?.value,
power: data['61.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 2,
current: data['71.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""}
};
// console.log(data);
this.voltages = [data['32.7.0']?.value, data['52.7.0']?.value, data['72.7.0']?.value];
this.realtime = { totalPower: data['1.7.0']?.value * 1000,
totalReactivePower: data['2.7.0']?.value * 1000,
totalExportEnergy: data['2.8.1']?.value + data['2.8.2']?.value,
totalImportEnergy: data['1.8.1']?.value + data['1.8.2']?.value,
monitorStatus: 0, utcTimeStamp: new Date().getTime() };
this.production = this.realtime.totalPower;
this.consumption = this.realtime.totalReactivePower;
}
}