homebridge-enphase-envoy
Version:
Homebridge plugin for Photovoltaic Energy System manufactured by Enphase.
127 lines (110 loc) • 4.69 kB
JavaScript
import express, { json } from 'express';
import EventEmitter from 'events';
const DEFAULT_MESSAGE = 'This data is not available in your system.';
class RestFul extends EventEmitter {
constructor(config) {
super();
this.port = config.port;
this.logWarn = config.logWarn;
this.logDebug = config.logDebug;
this.restFulData = {
token: DEFAULT_MESSAGE,
info: DEFAULT_MESSAGE,
home: DEFAULT_MESSAGE,
inventory: DEFAULT_MESSAGE,
inventorybyserialnumber: DEFAULT_MESSAGE,
microinvertersstatus: DEFAULT_MESSAGE,
meters: DEFAULT_MESSAGE,
metersreading: DEFAULT_MESSAGE,
metersreports: DEFAULT_MESSAGE,
detaileddevicesdata: DEFAULT_MESSAGE,
detaileddevicesdatabyserialnumber: DEFAULT_MESSAGE,
microinvertersdata: DEFAULT_MESSAGE,
qrelaysdata: DEFAULT_MESSAGE,
homedata: DEFAULT_MESSAGE,
metersdata: DEFAULT_MESSAGE,
production: DEFAULT_MESSAGE,
productionpdm: DEFAULT_MESSAGE,
energypdm: DEFAULT_MESSAGE,
productionct: DEFAULT_MESSAGE,
powerandenergydata: DEFAULT_MESSAGE,
energyhistory: DEFAULT_MESSAGE,
acbatterydata: DEFAULT_MESSAGE,
ensembleinventory: DEFAULT_MESSAGE,
ensemblestatus: DEFAULT_MESSAGE,
ensemblepower: DEFAULT_MESSAGE,
enchargesettings: DEFAULT_MESSAGE,
tariff: DEFAULT_MESSAGE,
drycontacts: DEFAULT_MESSAGE,
drycontactssettings: DEFAULT_MESSAGE,
generator: DEFAULT_MESSAGE,
generatorsettings: DEFAULT_MESSAGE,
ensembledata: DEFAULT_MESSAGE,
gridprofile: DEFAULT_MESSAGE,
livedata: DEFAULT_MESSAGE,
livedatadata: DEFAULT_MESSAGE,
productionstate: DEFAULT_MESSAGE,
plclevel: DEFAULT_MESSAGE,
datasampling: DEFAULT_MESSAGE
};
this.connect();
}
connect() {
try {
const app = express();
app.set('json spaces', 2);
app.use(json());
// Create GET routes directly from field names
for (const key of Object.keys(this.restFulData)) {
app.get(`/${key}`, (req, res) => {
res.json(this.restFulData[key]);
});
}
// PV
app.get('/pv', (req, res) => {
res.json(this.restFulData);
});
// Health check route
app.get('/status', (req, res) => {
res.json({
status: 'online',
uptime: process.uptime(),
available_paths: Object.keys(this.restFulData).map(k => `/${k}`)
});
});
// POST route
app.post('/', (req, res) => {
try {
const obj = req.body;
if (!obj || typeof obj !== 'object' || Object.keys(obj).length === 0) {
if (this.logWarn) this.emit('warn', 'RESTFul Invalid JSON payload');
return res.status(400).json({ error: 'RESTFul Invalid JSON payload' });
}
const key = Object.keys(obj)[0];
const value = obj[key];
this.emit('set', key, value);
this.update(key, value);
if (this.logDebug) this.emit('debug', `RESTFul post data: ${JSON.stringify(obj, null, 2)}`);
res.json({ success: true, received: obj });
} catch (error) {
if (this.logWarn) this.emit('warn', `RESTFul Parse error: ${error}`);
res.status(500).json({ error: 'RESTFul Internal Server Error' });
}
});
app.listen(this.port, () => {
this.emit('connected', `RESTful started on port: ${this.port}`);
});
} catch (error) {
if (this.logWarn) this.emit('warn', `RESTful Connect error: ${error}`);
}
}
update(path, data) {
if (this.restFulData.hasOwnProperty(path)) {
this.restFulData[path] = data;
if (this.logDebug) this.emit('debug', `RESTFul update path: ${path}, data: ${JSON.stringify(data, null, 2)}`);
} else {
if (this.logWarn) this.emit('warn', `RESTFul update failed. Unknown path: "${path}". Valid paths: ${Object.keys(this.restFulData).join(', ')}`);
}
}
}
export default RestFul;